openTEPES 4.18.7__py3-none-any.whl → 4.18.9__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openTEPES/__init__.py +1 -1
- openTEPES/openTEPES.py +3 -4
- openTEPES/openTEPES_InputData.py +213 -113
- openTEPES/openTEPES_Main.py +17 -7
- openTEPES/openTEPES_ModelFormulation.py +101 -60
- openTEPES/openTEPES_OutputResults.py +496 -196
- openTEPES/openTEPES_ProblemSolving.py +35 -34
- openTEPES/sSEP/oT_Data_RampReserveDown_sSEP.csv +8737 -0
- openTEPES/sSEP/oT_Data_RampReserveUp_sSEP.csv +8737 -0
- {opentepes-4.18.7.dist-info → opentepes-4.18.9.dist-info}/METADATA +20 -19
- {opentepes-4.18.7.dist-info → opentepes-4.18.9.dist-info}/RECORD +14 -12
- {opentepes-4.18.7.dist-info → opentepes-4.18.9.dist-info}/WHEEL +0 -0
- {opentepes-4.18.7.dist-info → opentepes-4.18.9.dist-info}/entry_points.txt +0 -0
- {opentepes-4.18.7.dist-info → opentepes-4.18.9.dist-info}/licenses/LICENSE +0 -0
openTEPES/openTEPES_InputData.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
|
-
Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) -
|
|
2
|
+
Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - January 19, 2026
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
import datetime
|
|
6
5
|
import time
|
|
7
6
|
import math
|
|
8
7
|
import os
|
|
@@ -11,6 +10,10 @@ from collections import defaultdict
|
|
|
11
10
|
from pyomo.environ import DataPortal, Set, Param, Var, Binary, NonNegativeReals, NonNegativeIntegers, PositiveReals, PositiveIntegers, Reals, UnitInterval, Any
|
|
12
11
|
from pyomo.environ import Block, Boolean
|
|
13
12
|
|
|
13
|
+
# from line_profiler import profile
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# @profile
|
|
14
17
|
def InputData(DirName, CaseName, mTEPES, pIndLogConsole):
|
|
15
18
|
print('Input data ****')
|
|
16
19
|
|
|
@@ -49,6 +52,8 @@ def InputData(DirName, CaseName, mTEPES, pIndLogConsole):
|
|
|
49
52
|
'VariablePTDF' : [0, 1, 2, 3],
|
|
50
53
|
}
|
|
51
54
|
FLAG_MAPPING = {
|
|
55
|
+
'RampReserveUp' : ('pIndRampReserves', None, 'No ramp reserves' ),
|
|
56
|
+
'RampReserveDown' : ('pIndRampReserves', None, 'No ramp reserves' ),
|
|
52
57
|
'VariableTTCFrw' : ('pIndVarTTC' , None, 'No variable transmission line TTCs' ),
|
|
53
58
|
'VariableTTCBck' : ('pIndVarTTC' , None, 'No variable transmission line TTCs' ),
|
|
54
59
|
'VariablePTDF' : ('pIndPTDF' , None, 'No flow-based market coupling method'),
|
|
@@ -122,8 +127,8 @@ def InputData(DirName, CaseName, mTEPES, pIndLogConsole):
|
|
|
122
127
|
return dfs, par
|
|
123
128
|
|
|
124
129
|
dfs, par = read_input_data(_path, CaseName)
|
|
125
|
-
# if 'pIndVarTTC', 'pIndPTDF', 'pIndHydroTopology', 'pIndHydrogen', 'pIndHeat' not in par include them and set value to zero
|
|
126
|
-
for key in ['pIndVarTTC', 'pIndPTDF', 'pIndHydroTopology', 'pIndHydrogen', 'pIndHeat']:
|
|
130
|
+
# if 'pIndRampReserves', 'pIndVarTTC', 'pIndPTDF', 'pIndHydroTopology', 'pIndHydrogen', 'pIndHeat' not in par include them and set value to zero
|
|
131
|
+
for key in ['pIndRampReserves', 'pIndVarTTC', 'pIndPTDF', 'pIndHydroTopology', 'pIndHydrogen', 'pIndHeat']:
|
|
127
132
|
if key not in par.keys():
|
|
128
133
|
par[key] = 0
|
|
129
134
|
|
|
@@ -149,7 +154,7 @@ def InputData(DirName, CaseName, mTEPES, pIndLogConsole):
|
|
|
149
154
|
'VariableFuelCost',
|
|
150
155
|
'VariableEmissionCost',]
|
|
151
156
|
mTEPES.node_frames_suffixes = ['Demand', 'Inertia']
|
|
152
|
-
mTEPES.area_frames_suffixes = ['OperatingReserveUp', 'OperatingReserveDown', 'ReserveMargin', 'Emission', 'RESEnergy']
|
|
157
|
+
mTEPES.area_frames_suffixes = ['RampReserveUp', 'RampReserveDown', 'OperatingReserveUp', 'OperatingReserveDown', 'ReserveMargin', 'Emission', 'RESEnergy']
|
|
153
158
|
mTEPES.hydro_frames_suffixes = ['Reservoir', 'VariableMinVolume', 'VariableMaxVolume', 'HydroInflows', 'HydroOutflows']
|
|
154
159
|
mTEPES.hydrogen_frames_suffixes = ['DemandHydrogen']
|
|
155
160
|
mTEPES.heat_frames_suffixes = ['DemandHeat', 'ReserveMarginHeat']
|
|
@@ -238,22 +243,26 @@ def InputData(DirName, CaseName, mTEPES, pIndLogConsole):
|
|
|
238
243
|
par['pReserveMargin'] = dfs['dfReserveMargin']['ReserveMargin' ] # minimum adequacy reserve margin [p.u.]
|
|
239
244
|
par['pEmission'] = dfs['dfEmission'] ['CO2Emission' ] # maximum CO2 emission [MtCO2]
|
|
240
245
|
par['pRESEnergy'] = dfs['dfRESEnergy'] ['RESEnergy' ] # minimum RES energy [GWh]
|
|
241
|
-
par['pDemandElec'] = dfs['dfDemand'].reindex
|
|
242
|
-
par['pSystemInertia'] = dfs['dfInertia'].reindex
|
|
243
|
-
par['pOperReserveUp'] = dfs['dfOperatingReserveUp'].reindex
|
|
244
|
-
par['pOperReserveDw'] = dfs['dfOperatingReserveDown'].reindex
|
|
245
|
-
par['pVariableMinPowerElec'] = dfs['dfVariableMinGeneration'].reindex
|
|
246
|
-
par['pVariableMaxPowerElec'] = dfs['dfVariableMaxGeneration'].reindex
|
|
246
|
+
par['pDemandElec'] = dfs['dfDemand' ].reindex(columns=mTEPES.nd, fill_value=0.0) * 1e-3 # electric demand [GW]
|
|
247
|
+
par['pSystemInertia'] = dfs['dfInertia' ].reindex(columns=mTEPES.ar, fill_value=0.0) # inertia [s]
|
|
248
|
+
par['pOperReserveUp'] = dfs['dfOperatingReserveUp' ].reindex(columns=mTEPES.ar, fill_value=0.0) * 1e-3 # upward operating reserve [GW]
|
|
249
|
+
par['pOperReserveDw'] = dfs['dfOperatingReserveDown' ].reindex(columns=mTEPES.ar, fill_value=0.0) * 1e-3 # downward operating reserve [GW]
|
|
250
|
+
par['pVariableMinPowerElec'] = dfs['dfVariableMinGeneration' ].reindex(columns=mTEPES.gg, fill_value=0.0) * 1e-3 # dynamic variable minimum power [GW]
|
|
251
|
+
par['pVariableMaxPowerElec'] = dfs['dfVariableMaxGeneration' ].reindex(columns=mTEPES.gg, fill_value=0.0) * 1e-3 # dynamic variable maximum power [GW]
|
|
247
252
|
par['pVariableMinCharge'] = dfs['dfVariableMinConsumption'].reindex(columns=mTEPES.gg, fill_value=0.0) * 1e-3 # dynamic variable minimum charge [GW]
|
|
248
253
|
par['pVariableMaxCharge'] = dfs['dfVariableMaxConsumption'].reindex(columns=mTEPES.gg, fill_value=0.0) * 1e-3 # dynamic variable maximum charge [GW]
|
|
249
|
-
par['pVariableMinStorage'] = dfs['dfVariableMinStorage'].reindex
|
|
250
|
-
par['pVariableMaxStorage'] = dfs['dfVariableMaxStorage'].reindex
|
|
251
|
-
par['pVariableMinEnergy'] = dfs['dfVariableMinEnergy'].reindex
|
|
252
|
-
par['pVariableMaxEnergy'] = dfs['dfVariableMaxEnergy'].reindex
|
|
253
|
-
par['pVariableFuelCost'] = dfs['dfVariableFuelCost'].reindex
|
|
254
|
-
par['pVariableEmissionCost'] = dfs['dfVariableEmissionCost'].reindex
|
|
255
|
-
par['pEnergyInflows'] = dfs['dfEnergyInflows'].reindex
|
|
256
|
-
par['pEnergyOutflows'] = dfs['dfEnergyOutflows'].reindex
|
|
254
|
+
par['pVariableMinStorage'] = dfs['dfVariableMinStorage' ].reindex(columns=mTEPES.gg, fill_value=0.0) # dynamic variable minimum storage [GWh]
|
|
255
|
+
par['pVariableMaxStorage'] = dfs['dfVariableMaxStorage' ].reindex(columns=mTEPES.gg, fill_value=0.0) # dynamic variable maximum storage [GWh]
|
|
256
|
+
par['pVariableMinEnergy'] = dfs['dfVariableMinEnergy' ].reindex(columns=mTEPES.gg, fill_value=0.0) * 1e-3 # dynamic variable minimum energy [GW]
|
|
257
|
+
par['pVariableMaxEnergy'] = dfs['dfVariableMaxEnergy' ].reindex(columns=mTEPES.gg, fill_value=0.0) * 1e-3 # dynamic variable maximum energy [GW]
|
|
258
|
+
par['pVariableFuelCost'] = dfs['dfVariableFuelCost' ].reindex(columns=mTEPES.gg, fill_value=0.0) # dynamic variable fuel cost [EUR/MJ]
|
|
259
|
+
par['pVariableEmissionCost'] = dfs['dfVariableEmissionCost' ].reindex(columns=mTEPES.gg, fill_value=0.0) # dynamic variable emission cost [EUR/tCO2]
|
|
260
|
+
par['pEnergyInflows'] = dfs['dfEnergyInflows' ].reindex(columns=mTEPES.gg, fill_value=0.0) * 1e-3 # dynamic energy inflows [GW]
|
|
261
|
+
par['pEnergyOutflows'] = dfs['dfEnergyOutflows' ].reindex(columns=mTEPES.gg, fill_value=0.0) * 1e-3 # dynamic energy outflows [GW]
|
|
262
|
+
|
|
263
|
+
if par['pIndRampReserves'] == 1:
|
|
264
|
+
par['pRampReserveUp'] = dfs['dfRampReserveUp' ].reindex(columns=mTEPES.ar, fill_value=0.0) * 1e-3 # system ramp up reserves [GW/h]
|
|
265
|
+
par['pRampReserveDw'] = dfs['dfRampReserveDown' ].reindex(columns=mTEPES.ar, fill_value=0.0) * 1e-3 # system ramp down reserves [GW/h]
|
|
257
266
|
|
|
258
267
|
if par['pIndVarTTC'] == 1:
|
|
259
268
|
par['pVariableNTCFrw'] = dfs['dfVariableTTCFrw'] * 1e-3 # variable TTC forward [GW]
|
|
@@ -262,10 +271,10 @@ def InputData(DirName, CaseName, mTEPES, pIndLogConsole):
|
|
|
262
271
|
par['pVariablePTDF'] = dfs['dfVariablePTDF'] # variable PTDF [p.u.]
|
|
263
272
|
|
|
264
273
|
if par['pIndHydroTopology'] == 1:
|
|
265
|
-
par['pVariableMinVolume'] = dfs['dfVariableMinVolume'].reindex
|
|
266
|
-
par['pVariableMaxVolume'] = dfs['dfVariableMaxVolume'].reindex
|
|
267
|
-
par['pHydroInflows'] = dfs['dfHydroInflows'].reindex
|
|
268
|
-
par['pHydroOutflows'] = dfs['dfHydroOutflows'].reindex
|
|
274
|
+
par['pVariableMinVolume'] = dfs['dfVariableMinVolume'].reindex(columns=mTEPES.rs, fill_value=0.0) # dynamic variable minimum reservoir volume [hm3]
|
|
275
|
+
par['pVariableMaxVolume'] = dfs['dfVariableMaxVolume'].reindex(columns=mTEPES.rs, fill_value=0.0) # dynamic variable maximum reservoir volume [hm3]
|
|
276
|
+
par['pHydroInflows'] = dfs['dfHydroInflows' ].reindex(columns=mTEPES.rs, fill_value=0.0) # dynamic hydro inflows [m3/s]
|
|
277
|
+
par['pHydroOutflows'] = dfs['dfHydroOutflows' ].reindex(columns=mTEPES.rs, fill_value=0.0) # dynamic hydro outflows [m3/s]
|
|
269
278
|
|
|
270
279
|
if par['pIndHydrogen'] == 1:
|
|
271
280
|
par['pDemandH2'] = dfs['dfDemandHydrogen'] [mTEPES.nd] # hydrogen demand [tH2/h]
|
|
@@ -301,6 +310,10 @@ def InputData(DirName, CaseName, mTEPES, pIndLogConsole):
|
|
|
301
310
|
par['pEnergyInflows'] = ProcessParameter(par['pEnergyInflows'], par['pTimeStep'])
|
|
302
311
|
par['pEnergyOutflows'] = ProcessParameter(par['pEnergyOutflows'], par['pTimeStep'])
|
|
303
312
|
|
|
313
|
+
if par['pIndRampReserves'] == 1:
|
|
314
|
+
par['pRampReserveUp'] = ProcessParameter(par['pRampReserveUp'], par['pTimeStep'])
|
|
315
|
+
par['pRampReserveDw'] = ProcessParameter(par['pRampReserveDw'], par['pTimeStep'])
|
|
316
|
+
|
|
304
317
|
if par['pIndVarTTC'] == 1:
|
|
305
318
|
par['pVariableNTCFrw'] = ProcessParameter(par['pVariableNTCFrw'], par['pTimeStep'])
|
|
306
319
|
par['pVariableNTCBck'] = ProcessParameter(par['pVariableNTCBck'], par['pTimeStep'])
|
|
@@ -497,6 +510,7 @@ def InputData(DirName, CaseName, mTEPES, pIndLogConsole):
|
|
|
497
510
|
print('Reading input data ... ', round(ReadingDataTime), 's')
|
|
498
511
|
|
|
499
512
|
|
|
513
|
+
# @profile
|
|
500
514
|
def DataConfiguration(mTEPES):
|
|
501
515
|
|
|
502
516
|
StartTime = time.time()
|
|
@@ -649,12 +663,11 @@ def DataConfiguration(mTEPES):
|
|
|
649
663
|
mTEPES.plc = Set(initialize = [(p, ni,nf,cc) for p, ni,nf,cc in mTEPES.p *mTEPES.lc if (p,ni,nf,cc) in mTEPES.pla])
|
|
650
664
|
mTEPES.pll = Set(initialize = [(p, ni,nf,cc) for p, ni,nf,cc in mTEPES.p *mTEPES.ll if (p,ni,nf,cc) in mTEPES.pla])
|
|
651
665
|
|
|
652
|
-
mTEPES.psc = Set(initialize = [(p,sc ) for p,sc in mTEPES.p *mTEPES.sc])
|
|
653
666
|
mTEPES.psg = Set(initialize = [(p,sc, g ) for p,sc, g in mTEPES.ps *mTEPES.g if (p,g ) in mTEPES.pg ])
|
|
654
667
|
mTEPES.psnr = Set(initialize = [(p,sc, nr) for p,sc, nr in mTEPES.ps *mTEPES.nr if (p,nr) in mTEPES.pnr ])
|
|
655
668
|
mTEPES.pses = Set(initialize = [(p,sc, es) for p,sc, es in mTEPES.ps *mTEPES.es if (p,es) in mTEPES.pes ])
|
|
656
669
|
mTEPES.pseh = Set(initialize = [(p,sc, eh) for p,sc, eh in mTEPES.ps *mTEPES.eh if (p,eh) in mTEPES.peh ])
|
|
657
|
-
mTEPES.psn = Set(initialize = [(p,sc,n ) for p,sc,n in mTEPES.ps *mTEPES.n
|
|
670
|
+
mTEPES.psn = Set(initialize = [(p,sc,n ) for p,sc,n in mTEPES.ps *mTEPES.n if mTEPES.dPar['pDuration'][p,sc,n]])
|
|
658
671
|
mTEPES.psng = Set(initialize = [(p,sc,n,g ) for p,sc,n,g in mTEPES.psn*mTEPES.g if (p,g ) in mTEPES.pg ])
|
|
659
672
|
mTEPES.psngc = Set(initialize = [(p,sc,n,gc) for p,sc,n,gc in mTEPES.psn*mTEPES.gc if (p,gc) in mTEPES.pgc ])
|
|
660
673
|
mTEPES.psngb = Set(initialize = [(p,sc,n,gb) for p,sc,n,gb in mTEPES.psn*mTEPES.gb if (p,gb) in mTEPES.pgc ])
|
|
@@ -670,10 +683,10 @@ def DataConfiguration(mTEPES):
|
|
|
670
683
|
mTEPES.psnnd = Set(initialize = [(p,sc,n,nd) for p,sc,n,nd in mTEPES.psn*mTEPES.nd ])
|
|
671
684
|
mTEPES.psnar = Set(initialize = [(p,sc,n,ar) for p,sc,n,ar in mTEPES.psn*mTEPES.ar ])
|
|
672
685
|
|
|
673
|
-
mTEPES.psnla = Set(initialize = [(p,sc,n,ni,nf,cc) for p,sc,n,ni,nf,cc in mTEPES.psn*mTEPES.la
|
|
674
|
-
mTEPES.psnle = Set(initialize = [(p,sc,n,ni,nf,cc) for p,sc,n,ni,nf,cc in mTEPES.psn*mTEPES.le
|
|
675
|
-
mTEPES.psnll = Set(initialize = [(p,sc,n,ni,nf,cc) for p,sc,n,ni,nf,cc in mTEPES.psn*mTEPES.ll
|
|
676
|
-
mTEPES.psnls = Set(initialize = [(p,sc,n,ni,nf,cc) for p,sc,n,ni,nf,cc in mTEPES.psn*mTEPES.ls
|
|
686
|
+
mTEPES.psnla = Set(initialize = [(p,sc,n,ni,nf,cc) for p,sc,n,ni,nf,cc in mTEPES.psn*mTEPES.la if (p,ni,nf,cc) in mTEPES.pla ])
|
|
687
|
+
mTEPES.psnle = Set(initialize = [(p,sc,n,ni,nf,cc) for p,sc,n,ni,nf,cc in mTEPES.psn*mTEPES.le if (p,ni,nf,cc) in mTEPES.pla ])
|
|
688
|
+
mTEPES.psnll = Set(initialize = [(p,sc,n,ni,nf,cc) for p,sc,n,ni,nf,cc in mTEPES.psn*mTEPES.ll if (p,ni,nf,cc) in mTEPES.pll ])
|
|
689
|
+
mTEPES.psnls = Set(initialize = [(p,sc,n,ni,nf,cc) for p,sc,n,ni,nf,cc in mTEPES.psn*mTEPES.ls if (p,ni,nf,cc) in mTEPES.pla ])
|
|
677
690
|
|
|
678
691
|
mTEPES.psnehc = Set(initialize = [(p,sc,n,eh) for p,sc,n,eh in mTEPES.psneh if mTEPES.dPar['pRatedMaxCharge'][eh] > 0.0 ])
|
|
679
692
|
|
|
@@ -998,20 +1011,20 @@ def DataConfiguration(mTEPES):
|
|
|
998
1011
|
# initial inventory must be between minimum and maximum
|
|
999
1012
|
for p,sc,n,es in mTEPES.psnes:
|
|
1000
1013
|
if (p,sc,st,n) in mTEPES.s2n and mTEPES.n.ord(n) == mTEPES.dPar['pStorageTimeStep'][es]:
|
|
1001
|
-
if mTEPES.dPar['pIniInventory']
|
|
1002
|
-
mTEPES.dPar['pIniInventory']
|
|
1003
|
-
print('### Initial inventory lower than minimum storage ',
|
|
1004
|
-
if mTEPES.dPar['pIniInventory']
|
|
1005
|
-
mTEPES.dPar['pIniInventory']
|
|
1014
|
+
if mTEPES.dPar['pIniInventory'].at[(p,sc,n),es] < mTEPES.dPar['pMinStorage'].at[(p,sc,n),es]:
|
|
1015
|
+
mTEPES.dPar['pIniInventory'].at[(p,sc,n),es] = mTEPES.dPar['pMinStorage'].at[(p,sc,n),es]
|
|
1016
|
+
print('### Initial inventory lower than minimum storage ', p, sc, st, es)
|
|
1017
|
+
if mTEPES.dPar['pIniInventory'].at[(p,sc,n),es] > mTEPES.dPar['pMaxStorage'].at[(p,sc,n),es]:
|
|
1018
|
+
mTEPES.dPar['pIniInventory'].at[(p,sc,n),es] = mTEPES.dPar['pMaxStorage'].at[(p,sc,n),es]
|
|
1006
1019
|
print('### Initial inventory greater than maximum storage ', p, sc, st, es)
|
|
1007
1020
|
if mTEPES.dPar['pIndHydroTopology'] == 1:
|
|
1008
1021
|
for p,sc,n,rs in mTEPES.psnrs:
|
|
1009
1022
|
if (p,sc,st,n) in mTEPES.s2n and mTEPES.n.ord(n) == mTEPES.dPar['pReservoirTimeStep'][rs]:
|
|
1010
|
-
if mTEPES.dPar['pIniVolume']
|
|
1011
|
-
mTEPES.dPar['pIniVolume']
|
|
1023
|
+
if mTEPES.dPar['pIniVolume'].at[(p,sc,n),rs] < mTEPES.dPar['pMinVolume'].at[(p,sc,n),rs]:
|
|
1024
|
+
mTEPES.dPar['pIniVolume'].at[(p,sc,n),rs] = mTEPES.dPar['pMinVolume'].at[(p,sc,n),rs]
|
|
1012
1025
|
print('### Initial volume lower than minimum volume ', p, sc, st, rs)
|
|
1013
|
-
if mTEPES.dPar['pIniVolume']
|
|
1014
|
-
mTEPES.dPar['pIniVolume']
|
|
1026
|
+
if mTEPES.dPar['pIniVolume'].at[(p,sc,n),rs] > mTEPES.dPar['pMaxVolume'].at[(p,sc,n),rs]:
|
|
1027
|
+
mTEPES.dPar['pIniVolume'].at[(p,sc,n),rs] = mTEPES.dPar['pMaxVolume'].at[(p,sc,n),rs]
|
|
1015
1028
|
print('### Initial volume greater than maximum volume ', p, sc, st, rs)
|
|
1016
1029
|
|
|
1017
1030
|
# drop load levels with duration 0
|
|
@@ -1044,8 +1057,12 @@ def DataConfiguration(mTEPES):
|
|
|
1044
1057
|
mTEPES.dPar['pOutflowsTimeStep'] = mTEPES.dPar['pOutflowsTimeStep'].loc [mTEPES.es ]
|
|
1045
1058
|
mTEPES.dPar['pStorageType'] = mTEPES.dPar['pStorageType'].loc [mTEPES.es ]
|
|
1046
1059
|
|
|
1060
|
+
if mTEPES.dPar['pIndRampReserves'] == 1:
|
|
1061
|
+
mTEPES.dPar['pRampReserveUp'] = mTEPES.dPar['pRampReserveUp'].loc [mTEPES.psnar]
|
|
1062
|
+
mTEPES.dPar['pRampReserveDw'] = mTEPES.dPar['pRampReserveDw'].loc [mTEPES.psnar]
|
|
1063
|
+
|
|
1047
1064
|
if mTEPES.dPar['pIndHydroTopology'] == 1:
|
|
1048
|
-
mTEPES.dPar['pHydroInflows']
|
|
1065
|
+
mTEPES.dPar['pHydroInflows' ] = mTEPES.dPar['pHydroInflows' ].loc [mTEPES.psn ]
|
|
1049
1066
|
mTEPES.dPar['pHydroOutflows'] = mTEPES.dPar['pHydroOutflows'].loc [mTEPES.psn ]
|
|
1050
1067
|
mTEPES.dPar['pIniVolume'] = mTEPES.dPar['pIniVolume'].loc [mTEPES.psn ]
|
|
1051
1068
|
mTEPES.dPar['pMinVolume'] = mTEPES.dPar['pMinVolume'].loc [mTEPES.psn ]
|
|
@@ -1134,7 +1151,7 @@ def DataConfiguration(mTEPES):
|
|
|
1134
1151
|
# mTEPES.dPar['pMaxPowerElec'] = mTEPES.dPar['pMaxPowerElec'].where(mTEPES.dPar['pMaxPowerElec'] >= mTEPES.dPar['pMinPowerElec'], mTEPES.dPar['pMinPowerElec'])
|
|
1135
1152
|
# mTEPES.dPar['pMaxCharge'] = mTEPES.dPar['pMaxCharge'].where (mTEPES.dPar['pMaxCharge'] >= mTEPES.dPar['pMinCharge'], mTEPES.dPar['pMinCharge'] )
|
|
1136
1153
|
|
|
1137
|
-
# Decrease
|
|
1154
|
+
# Decrease minimum to reach maximum
|
|
1138
1155
|
mTEPES.dPar['pMinPowerElec'] = mTEPES.dPar['pMinPowerElec'].where(mTEPES.dPar['pMinPowerElec'] <= mTEPES.dPar['pMaxPowerElec'], mTEPES.dPar['pMaxPowerElec'])
|
|
1139
1156
|
mTEPES.dPar['pMinCharge'] = mTEPES.dPar['pMinCharge'].where (mTEPES.dPar['pMinCharge'] <= mTEPES.dPar['pMaxCharge'], mTEPES.dPar['pMaxCharge'] )
|
|
1140
1157
|
|
|
@@ -1363,6 +1380,10 @@ def DataConfiguration(mTEPES):
|
|
|
1363
1380
|
mTEPES.dPar['pOperReserveUp'] = filter_rows(mTEPES.dPar['pOperReserveUp'] , mTEPES.psnar)
|
|
1364
1381
|
mTEPES.dPar['pOperReserveDw'] = filter_rows(mTEPES.dPar['pOperReserveDw'] , mTEPES.psnar)
|
|
1365
1382
|
|
|
1383
|
+
if mTEPES.dPar['pIndRampReserves'] == 1:
|
|
1384
|
+
mTEPES.dPar['pRampReserveUp'] = filter_rows(mTEPES.dPar['pRampReserveUp'] , mTEPES.psnar)
|
|
1385
|
+
mTEPES.dPar['pRampReserveDw'] = filter_rows(mTEPES.dPar['pRampReserveDw'] , mTEPES.psnar)
|
|
1386
|
+
|
|
1366
1387
|
mTEPES.dPar['pMaxNTCBck'] = filter_rows(mTEPES.dPar['pMaxNTCBck'] , mTEPES.psnla)
|
|
1367
1388
|
mTEPES.dPar['pMaxNTCFrw'] = filter_rows(mTEPES.dPar['pMaxNTCFrw'] , mTEPES.psnla)
|
|
1368
1389
|
mTEPES.dPar['pMaxNTCMax'] = filter_rows(mTEPES.dPar['pMaxNTCMax'] , mTEPES.psnla)
|
|
@@ -1386,6 +1407,7 @@ def DataConfiguration(mTEPES):
|
|
|
1386
1407
|
mTEPES.pIndBinGenMinTime = Param(initialize=mTEPES.dPar['pIndBinGenMinTime'] , within=Binary, doc='Indicator of using or not the min up/dw time constraints', mutable=True)
|
|
1387
1408
|
mTEPES.pIndBinLineCommit = Param(initialize=mTEPES.dPar['pIndBinLineCommit'] , within=Binary, doc='Indicator of binary electric network switching decisions', mutable=True)
|
|
1388
1409
|
mTEPES.pIndBinNetLosses = Param(initialize=mTEPES.dPar['pIndBinNetLosses'] , within=Binary, doc='Indicator of binary electric network ohmic losses', mutable=True)
|
|
1410
|
+
mTEPES.pIndRampReserves = Param(initialize=mTEPES.dPar['pIndRampReserves'] , within=Binary, doc='Indicator of ramp reserves' )
|
|
1389
1411
|
mTEPES.pIndHydroTopology = Param(initialize=mTEPES.dPar['pIndHydroTopology'] , within=Binary, doc='Indicator of reservoir and hydropower topology' )
|
|
1390
1412
|
mTEPES.pIndHydrogen = Param(initialize=mTEPES.dPar['pIndHydrogen'] , within=Binary, doc='Indicator of hydrogen demand and pipeline network' )
|
|
1391
1413
|
mTEPES.pIndHeat = Param(initialize=mTEPES.dPar['pIndHeat'] , within=Binary, doc='Indicator of heat demand and pipe network' )
|
|
@@ -1413,7 +1435,7 @@ def DataConfiguration(mTEPES):
|
|
|
1413
1435
|
mTEPES.pDemandElecPos = Param(mTEPES.psnnd, initialize=mTEPES.dPar['pDemandElecPos'].to_dict() , within=NonNegativeReals, doc='Electric demand positive' )
|
|
1414
1436
|
mTEPES.pPeriodWeight = Param(mTEPES.p, initialize=mTEPES.dPar['pPeriodWeight'].to_dict() , within=NonNegativeReals, doc='Period weight', mutable=True)
|
|
1415
1437
|
mTEPES.pDiscountedWeight = Param(mTEPES.p, initialize=mTEPES.dPar['pDiscountedWeight'].to_dict() , within=NonNegativeReals, doc='Discount factor' )
|
|
1416
|
-
mTEPES.pScenProb = Param(mTEPES.
|
|
1438
|
+
mTEPES.pScenProb = Param(mTEPES.ps, initialize=mTEPES.dPar['pScenProb'].to_dict() , within=UnitInterval , doc='Probability', mutable=True)
|
|
1417
1439
|
mTEPES.pStageWeight = Param(mTEPES.stt, initialize=mTEPES.dPar['pStageWeight'].to_dict() , within=NonNegativeReals, doc='Stage weight' )
|
|
1418
1440
|
mTEPES.pDuration = Param(mTEPES.psn, initialize=mTEPES.dPar['pDuration'].to_dict() , within=NonNegativeIntegers, doc='Duration', mutable=True)
|
|
1419
1441
|
mTEPES.pNodeLon = Param(mTEPES.nd, initialize=mTEPES.dPar['pNodeLon'].to_dict() , doc='Longitude' )
|
|
@@ -1477,6 +1499,10 @@ def DataConfiguration(mTEPES):
|
|
|
1477
1499
|
mTEPES.pGenLoRetire = Param(mTEPES.gd, initialize=mTEPES.dPar['pGenLoRetire'].to_dict() , within=NonNegativeReals, doc='Lower bound of the retirement decision', mutable=True)
|
|
1478
1500
|
mTEPES.pGenUpRetire = Param(mTEPES.gd, initialize=mTEPES.dPar['pGenUpRetire'].to_dict() , within=NonNegativeReals, doc='Upper bound of the retirement decision', mutable=True)
|
|
1479
1501
|
|
|
1502
|
+
if mTEPES.dPar['pIndRampReserves'] == 1:
|
|
1503
|
+
mTEPES.pRampReserveUp = Param(mTEPES.psnar, initialize=mTEPES.dPar['pRampReserveUp'].to_dict() , within=NonNegativeReals, doc='Ramp up reserve' )
|
|
1504
|
+
mTEPES.pRampReserveDw = Param(mTEPES.psnar, initialize=mTEPES.dPar['pRampReserveDw'].to_dict() , within=NonNegativeReals, doc='Ramp down reserve' )
|
|
1505
|
+
|
|
1480
1506
|
if mTEPES.dPar['pIndHydrogen'] == 1:
|
|
1481
1507
|
mTEPES.pProductionFunctionH2 = Param(mTEPES.el, initialize=mTEPES.dPar['pProductionFunctionH2'].to_dict(), within=NonNegativeReals, doc='Production function of an electrolyzer plant')
|
|
1482
1508
|
|
|
@@ -1663,6 +1689,7 @@ def DataConfiguration(mTEPES):
|
|
|
1663
1689
|
print('Setting up input data ... ', round(SettingUpDataTime), 's')
|
|
1664
1690
|
|
|
1665
1691
|
|
|
1692
|
+
# @profile
|
|
1666
1693
|
def SettingUpVariables(OptModel, mTEPES):
|
|
1667
1694
|
|
|
1668
1695
|
StartTime = time.time()
|
|
@@ -1701,6 +1728,10 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
1701
1728
|
OptModel.vESSSpillage = Var(mTEPES.psnes, within=NonNegativeReals, doc='ESS spillage [GWh]')
|
|
1702
1729
|
OptModel.vIniInventory = Var(mTEPES.psnec, within=NonNegativeReals, doc='initial inventory for ESS candidate [GWh]')
|
|
1703
1730
|
|
|
1731
|
+
if mTEPES.pIndRampReserves == 1:
|
|
1732
|
+
OptModel.vRampReserveUp = Var(mTEPES.psnnr, within=NonNegativeReals, doc='ramp up reserve of the unit [GW/h]')
|
|
1733
|
+
OptModel.vRampReserveDw = Var(mTEPES.psnnr, within=NonNegativeReals, doc='ramp down reserve of the unit [GW/h]')
|
|
1734
|
+
|
|
1704
1735
|
OptModel.vESSTotalCharge = Var(mTEPES.psneh, within=NonNegativeReals, doc='ESS total charge power [GW]')
|
|
1705
1736
|
OptModel.vCharge2ndBlock = Var(mTEPES.psneh, within=NonNegativeReals, doc='ESS charge power [GW]')
|
|
1706
1737
|
OptModel.vESSReserveUp = Var(mTEPES.psneh, within=NonNegativeReals, doc='ESS upward operating reserve [GW]')
|
|
@@ -1837,6 +1868,10 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
1837
1868
|
[OptModel.vIniInventory [p,sc,n,ec].setlb(mTEPES.pMinStorage [p,sc,n,ec] ) for p,sc,n,ec in mTEPES.psnec]
|
|
1838
1869
|
[OptModel.vIniInventory [p,sc,n,ec].setub(mTEPES.pMaxStorage [p,sc,n,ec] ) for p,sc,n,ec in mTEPES.psnec]
|
|
1839
1870
|
|
|
1871
|
+
if mTEPES.pIndRampReserves == 1:
|
|
1872
|
+
[OptModel.vRampReserveUp[p,sc,n,nr].setub(min(mTEPES.pMaxPower2ndBlock[p,sc,n,nr], mTEPES.pRampUp[nr])) if mTEPES.pRampUp[nr] else OptModel.vRampReserveUp[p,sc,n,nr].setub(mTEPES.pMaxPower2ndBlock[p,sc,n,nr]) for p,sc,n,nr in mTEPES.psnnr]
|
|
1873
|
+
[OptModel.vRampReserveDw[p,sc,n,nr].setub(min(mTEPES.pMaxPower2ndBlock[p,sc,n,nr], mTEPES.pRampDw[nr])) if mTEPES.pRampUp[nr] else OptModel.vRampReserveDw[p,sc,n,nr].setub(mTEPES.pMaxPower2ndBlock[p,sc,n,nr]) for p,sc,n,nr in mTEPES.psnnr]
|
|
1874
|
+
|
|
1840
1875
|
[OptModel.vESSTotalCharge[p,sc,n,eh].setub(mTEPES.pMaxCharge [p,sc,n,eh] ) for p,sc,n,eh in mTEPES.psneh]
|
|
1841
1876
|
[OptModel.vCharge2ndBlock[p,sc,n,eh].setub(mTEPES.pMaxCharge2ndBlock[p,sc,n,eh] ) for p,sc,n,eh in mTEPES.psneh]
|
|
1842
1877
|
[OptModel.vESSReserveUp [p,sc,n,eh].setub(mTEPES.pMaxCharge2ndBlock[p,sc,n,eh] ) for p,sc,n,eh in mTEPES.psneh]
|
|
@@ -1866,7 +1901,7 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
1866
1901
|
int: The number of fixed variables.
|
|
1867
1902
|
'''
|
|
1868
1903
|
|
|
1869
|
-
|
|
1904
|
+
nFixedVariables = 0
|
|
1870
1905
|
|
|
1871
1906
|
# relax binary condition in generation, boiler, and electric network investment decisions
|
|
1872
1907
|
for p,eb in mTEPES.peb:
|
|
@@ -1874,14 +1909,16 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
1874
1909
|
OptModel.vGenerationInvest [p,eb ].domain = UnitInterval
|
|
1875
1910
|
if mTEPES.pIndBinGenInvest() == 2:
|
|
1876
1911
|
OptModel.vGenerationInvest [p,eb ].fix(0)
|
|
1877
|
-
|
|
1912
|
+
OptModel.vGenerationInvest [p,eb ].domain = UnitInterval
|
|
1913
|
+
nFixedVariables += 1
|
|
1878
1914
|
|
|
1879
1915
|
for p,ni,nf,cc in mTEPES.plc:
|
|
1880
1916
|
if mTEPES.pIndBinNetElecInvest() != 0 and mTEPES.pIndBinLineInvest[ni,nf,cc] == 0:
|
|
1881
1917
|
OptModel.vNetworkInvest [p,ni,nf,cc].domain = UnitInterval
|
|
1882
1918
|
if mTEPES.pIndBinNetElecInvest() == 2:
|
|
1883
1919
|
OptModel.vNetworkInvest [p,ni,nf,cc].fix(0)
|
|
1884
|
-
|
|
1920
|
+
OptModel.vNetworkInvest [p,ni,nf,cc].domain = UnitInterval
|
|
1921
|
+
nFixedVariables += 1
|
|
1885
1922
|
|
|
1886
1923
|
# relax binary condition in generation retirement decisions
|
|
1887
1924
|
for p,gd in mTEPES.pgd:
|
|
@@ -1889,7 +1926,8 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
1889
1926
|
OptModel.vGenerationRetire [p,gd ].domain = UnitInterval
|
|
1890
1927
|
if mTEPES.pIndBinGenRetire() == 2:
|
|
1891
1928
|
OptModel.vGenerationRetire [p,gd ].fix(0)
|
|
1892
|
-
|
|
1929
|
+
OptModel.vGenerationRetire [p,gd ].domain = UnitInterval
|
|
1930
|
+
nFixedVariables += 1
|
|
1893
1931
|
|
|
1894
1932
|
# relax binary condition in reservoir investment decisions
|
|
1895
1933
|
if mTEPES.pIndHydroTopology == 1:
|
|
@@ -1898,7 +1936,8 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
1898
1936
|
OptModel.vReservoirInvest [p,rc ].domain = UnitInterval
|
|
1899
1937
|
if mTEPES.pIndBinRsrInvest() == 2:
|
|
1900
1938
|
OptModel.vReservoirInvest [p,rc ].fix(0)
|
|
1901
|
-
|
|
1939
|
+
OptModel.vReservoirInvest [p,rc ].domain = UnitInterval
|
|
1940
|
+
nFixedVariables += 1
|
|
1902
1941
|
|
|
1903
1942
|
# relax binary condition in hydrogen network investment decisions
|
|
1904
1943
|
if mTEPES.pIndHydrogen == 1:
|
|
@@ -1907,7 +1946,8 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
1907
1946
|
OptModel.vH2PipeInvest [p,ni,nf,cc].domain = UnitInterval
|
|
1908
1947
|
if mTEPES.pIndBinNetH2Invest() == 2:
|
|
1909
1948
|
OptModel.vH2PipeInvest [p,ni,nf,cc].fix(0)
|
|
1910
|
-
|
|
1949
|
+
OptModel.vH2PipeInvest [p,ni,nf,cc].domain = UnitInterval
|
|
1950
|
+
nFixedVariables += 1
|
|
1911
1951
|
|
|
1912
1952
|
if mTEPES.pIndHeat == 1:
|
|
1913
1953
|
# relax binary condition in heat network investment decisions
|
|
@@ -1916,7 +1956,8 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
1916
1956
|
OptModel.vHeatPipeInvest [p,ni,nf,cc].domain = UnitInterval
|
|
1917
1957
|
if mTEPES.pIndBinNetHeatInvest() == 2:
|
|
1918
1958
|
OptModel.vHeatPipeInvest [p,ni,nf,cc].fix(0)
|
|
1919
|
-
|
|
1959
|
+
OptModel.vHeatPipeInvest [p,ni,nf,cc].domain = UnitInterval
|
|
1960
|
+
nFixedVariables += 1
|
|
1920
1961
|
|
|
1921
1962
|
# relax binary condition in unit generation, startup and shutdown decisions
|
|
1922
1963
|
for p,sc,n,nr in mTEPES.psnnr:
|
|
@@ -1929,6 +1970,9 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
1929
1970
|
OptModel.vStableState [p,sc,n,nr].fix(0)
|
|
1930
1971
|
OptModel.vRampDwState [p,sc,n,nr].fix(0)
|
|
1931
1972
|
OptModel.vRampUpState [p,sc,n,nr].fix(0)
|
|
1973
|
+
OptModel.vStableState [p,sc,n,nr].domain = UnitInterval
|
|
1974
|
+
OptModel.vRampDwState [p,sc,n,nr].domain = UnitInterval
|
|
1975
|
+
OptModel.vRampUpState [p,sc,n,nr].domain = UnitInterval
|
|
1932
1976
|
|
|
1933
1977
|
for p,sc,nr, group in mTEPES.psnr * mTEPES.ExclusiveGroups:
|
|
1934
1978
|
if mTEPES.pIndBinUnitCommit[nr] == 0 and nr in mTEPES.ExclusiveGeneratorsYearly:
|
|
@@ -1942,9 +1986,10 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
1942
1986
|
OptModel.vCommitmentCons[p,sc,n,h].domain = UnitInterval
|
|
1943
1987
|
if mTEPES.pMaxCharge[p,sc,n,h] == 0.0:
|
|
1944
1988
|
OptModel.vCommitmentCons[p,sc,n,h].fix(0)
|
|
1945
|
-
|
|
1989
|
+
OptModel.vCommitmentCons[p,sc,n,h].domain = UnitInterval
|
|
1990
|
+
nFixedVariables += 1
|
|
1946
1991
|
|
|
1947
|
-
return
|
|
1992
|
+
return nFixedVariables
|
|
1948
1993
|
|
|
1949
1994
|
# call the relaxing variables function and add its output to nFixedVariables
|
|
1950
1995
|
nFixedBinaries = RelaxBinaryInvestmentConditions(mTEPES, mTEPES)
|
|
@@ -1967,14 +2012,21 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
1967
2012
|
|
|
1968
2013
|
nFixedVariables = 0
|
|
1969
2014
|
# existing lines are always committed if no switching decision is modeled
|
|
1970
|
-
|
|
1971
|
-
|
|
2015
|
+
for p,sc,n,ni,nf,cc in mTEPES.psnle:
|
|
2016
|
+
if mTEPES.pIndBinLineSwitch[ni,nf,cc] == 0:
|
|
2017
|
+
OptModel.vLineCommit[p,sc,n,ni,nf,cc].fix(1)
|
|
2018
|
+
OptModel.vLineCommit[p,sc,n,ni,nf,cc].domain = UnitInterval
|
|
2019
|
+
nFixedVariables += 1
|
|
1972
2020
|
|
|
1973
2021
|
# no on/off state for lines if no switching decision is modeled
|
|
1974
2022
|
if sum(mTEPES.pIndBinLineSwitch[:,:,:]):
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
2023
|
+
for p,sc,n,ni,nf,cc in mTEPES.psnla:
|
|
2024
|
+
if mTEPES.pIndBinLineSwitch[ni,nf,cc] == 0:
|
|
2025
|
+
OptModel.vLineOnState [p,sc,n,ni,nf,cc].fix(0)
|
|
2026
|
+
OptModel.vLineOffState[p,sc,n,ni,nf,cc].fix(0)
|
|
2027
|
+
OptModel.vLineOnState [p,sc,n,ni,nf,cc].domain = UnitInterval
|
|
2028
|
+
OptModel.vLineOffState[p,sc,n,ni,nf,cc].domain = UnitInterval
|
|
2029
|
+
nFixedVariables += 2
|
|
1978
2030
|
|
|
1979
2031
|
OptModel.vLineLosses = Var(mTEPES.psnll, within=NonNegativeReals, doc='half line losses [GW]')
|
|
1980
2032
|
OptModel.vFlowElec = Var(mTEPES.psnla, within=Reals, doc='electric flow [GW]')
|
|
@@ -1988,12 +2040,14 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
1988
2040
|
if mTEPES.pIndPTDF == 1:
|
|
1989
2041
|
OptModel.vNetPosition = Var(mTEPES.psnnd, within=Reals, doc='net position in node [GW]')
|
|
1990
2042
|
|
|
1991
|
-
[OptModel.vLineLosses[p,sc,n,ni,nf,cc].setub(0.5*mTEPES.pLineLossFactor[ni,nf,cc]*mTEPES.pLineNTCMax[ni,nf,cc]) for p,sc,n,ni,nf,cc in mTEPES.psnll]
|
|
1992
2043
|
if mTEPES.pIndBinSingleNode() == 0:
|
|
1993
|
-
[OptModel.
|
|
1994
|
-
[OptModel.vFlowElec[p,sc,n,ni,nf,cc].
|
|
1995
|
-
|
|
1996
|
-
|
|
2044
|
+
[OptModel.vLineLosses[p,sc,n,ni,nf,cc].setub(0.5*mTEPES.pLineLossFactor[ni,nf,cc]*mTEPES.pLineNTCMax[ni,nf,cc]) for p,sc,n,ni,nf,cc in mTEPES.psnll]
|
|
2045
|
+
[OptModel.vFlowElec [p,sc,n,ni,nf,cc].setlb(-mTEPES.pMaxNTCBck[p,sc,n,ni,nf,cc] ) for p,sc,n,ni,nf,cc in mTEPES.psnla]
|
|
2046
|
+
[OptModel.vFlowElec [p,sc,n,ni,nf,cc].setub( mTEPES.pMaxNTCFrw[p,sc,n,ni,nf,cc] ) for p,sc,n,ni,nf,cc in mTEPES.psnla]
|
|
2047
|
+
else:
|
|
2048
|
+
[OptModel.vLineLosses[p,sc,n,ni,nf,cc].fix(0.0) for p,sc,n,ni,nf,cc in mTEPES.psnll]
|
|
2049
|
+
[OptModel.vTheta [p,sc,n,nd ].setlb(-mTEPES.pMaxTheta [p,sc,n,nd ]()) for p,sc,n,nd in mTEPES.psnnd]
|
|
2050
|
+
[OptModel.vTheta [p,sc,n,nd ].setub( mTEPES.pMaxTheta [p,sc,n,nd ]()) for p,sc,n,nd in mTEPES.psnnd]
|
|
1997
2051
|
|
|
1998
2052
|
if mTEPES.pIndHydrogen == 1:
|
|
1999
2053
|
OptModel.vFlowH2 = Var(mTEPES.psnpa, within=Reals, doc='pipeline flow [tH2]')
|
|
@@ -2044,6 +2098,9 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
2044
2098
|
OptModel.vCommitment [p,sc,n,nr].fix(1)
|
|
2045
2099
|
OptModel.vStartUp [p,sc,n,nr].fix(0)
|
|
2046
2100
|
OptModel.vShutDown [p,sc,n,nr].fix(0)
|
|
2101
|
+
OptModel.vCommitment [p,sc,n,nr].domain = UnitInterval
|
|
2102
|
+
OptModel.vStartUp [p,sc,n,nr].domain = UnitInterval
|
|
2103
|
+
OptModel.vShutDown [p,sc,n,nr].domain = UnitInterval
|
|
2047
2104
|
nFixedVariables += 3
|
|
2048
2105
|
# If there are mutually exclusive groups do not fix variables from ESS in mutually exclusive groups
|
|
2049
2106
|
elif len(mTEPES.ExclusiveGroups) > 0 and nr not in mTEPES.ExclusiveGenerators:
|
|
@@ -2051,14 +2108,23 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
2051
2108
|
OptModel.vCommitment [p,sc,n,nr].fix(1)
|
|
2052
2109
|
OptModel.vStartUp [p,sc,n,nr].fix(0)
|
|
2053
2110
|
OptModel.vShutDown [p,sc,n,nr].fix(0)
|
|
2111
|
+
OptModel.vCommitment [p,sc,n,nr].domain = UnitInterval
|
|
2112
|
+
OptModel.vStartUp [p,sc,n,nr].domain = UnitInterval
|
|
2113
|
+
OptModel.vShutDown [p,sc,n,nr].domain = UnitInterval
|
|
2054
2114
|
nFixedVariables += 3
|
|
2055
2115
|
|
|
2056
|
-
# if min and max power coincide there are neither second block, nor operating reserve
|
|
2116
|
+
# if min and max power coincide there are neither second block, nor operating reserve, nor ramp reserve
|
|
2057
2117
|
if mTEPES.pMaxPower2ndBlock [p,sc,n,nr] == 0.0:
|
|
2058
2118
|
OptModel.vOutput2ndBlock [p,sc,n,nr].fix(0.0)
|
|
2059
2119
|
OptModel.vReserveUp [p,sc,n,nr].fix(0.0)
|
|
2060
2120
|
OptModel.vReserveDown [p,sc,n,nr].fix(0.0)
|
|
2061
2121
|
nFixedVariables += 3
|
|
2122
|
+
if mTEPES.pIndRampReserves == 1:
|
|
2123
|
+
if mTEPES.pMaxPower2ndBlock[p, sc, n, nr] == 0.0 or mTEPES.pRampUp[nr] == 0.0:
|
|
2124
|
+
OptModel.vRampReserveUp[p,sc,n,nr].fix(0.0)
|
|
2125
|
+
OptModel.vRampReserveDw[p,sc,n,nr].fix(0.0)
|
|
2126
|
+
nFixedVariables += 2
|
|
2127
|
+
|
|
2062
2128
|
if mTEPES.pIndOperReserveGen[ nr] == 1:
|
|
2063
2129
|
OptModel.vReserveUp [p,sc,n,nr].fix(0.0)
|
|
2064
2130
|
OptModel.vReserveDown [p,sc,n,nr].fix(0.0)
|
|
@@ -2100,7 +2166,8 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
2100
2166
|
# ESS with no charge capacity or not storage capacity can't charge
|
|
2101
2167
|
if mTEPES.pMaxCharge [p,sc,n,h ] == 0.0:
|
|
2102
2168
|
OptModel.vESSTotalCharge [p,sc,n,h ].fix(0.0)
|
|
2103
|
-
OptModel.vCommitmentCons [p,sc,n,h ].fix(0
|
|
2169
|
+
OptModel.vCommitmentCons [p,sc,n,h ].fix(0 )
|
|
2170
|
+
OptModel.vCommitmentCons [p,sc,n,h ].domain = UnitInterval
|
|
2104
2171
|
nFixedVariables += 2
|
|
2105
2172
|
if mTEPES.pMaxCharge2ndBlock[p,sc,n,h ] == 0.0:
|
|
2106
2173
|
OptModel.vCharge2ndBlock [p,sc,n,h ].fix(0.0)
|
|
@@ -2300,27 +2367,36 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
2300
2367
|
if mTEPES.pElecGenPeriodIni[eb] > p:
|
|
2301
2368
|
OptModel.vGenerationInvest[p,eb].fix(0)
|
|
2302
2369
|
OptModel.vGenerationInvPer[p,eb].fix(0)
|
|
2370
|
+
OptModel.vGenerationInvest[p,eb].domain = UnitInterval
|
|
2371
|
+
OptModel.vGenerationInvPer[p,eb].domain = UnitInterval
|
|
2303
2372
|
nFixedVariables += 2
|
|
2304
2373
|
if mTEPES.pElecGenPeriodFin[eb] < p:
|
|
2305
2374
|
OptModel.vGenerationInvPer[p,eb].fix(0)
|
|
2375
|
+
OptModel.vGenerationInvPer[p,eb].domain = UnitInterval
|
|
2306
2376
|
nFixedVariables += 1
|
|
2307
2377
|
|
|
2308
2378
|
for p,gd in mTEPES.pgd:
|
|
2309
2379
|
if mTEPES.pElecGenPeriodIni[gd] > p:
|
|
2310
2380
|
OptModel.vGenerationRetire[p,gd].fix(0)
|
|
2311
2381
|
OptModel.vGenerationRetPer[p,gd].fix(0)
|
|
2382
|
+
OptModel.vGenerationRetire[p,gd].domain = UnitInterval
|
|
2383
|
+
OptModel.vGenerationRetPer[p,gd].domain = UnitInterval
|
|
2312
2384
|
nFixedVariables += 2
|
|
2313
2385
|
if mTEPES.pElecGenPeriodFin[gd] < p:
|
|
2314
2386
|
OptModel.vGenerationRetPer[p,gd].fix(0)
|
|
2387
|
+
OptModel.vGenerationRetPer[p,gd].domain = UnitInterval
|
|
2315
2388
|
nFixedVariables += 1
|
|
2316
2389
|
|
|
2317
2390
|
for p,ni,nf,cc in mTEPES.plc:
|
|
2318
2391
|
if mTEPES.pElecNetPeriodIni[ni,nf,cc] > p:
|
|
2319
2392
|
OptModel.vNetworkInvest[p,ni,nf,cc].fix(0)
|
|
2320
2393
|
OptModel.vNetworkInvPer[p,ni,nf,cc].fix(0)
|
|
2394
|
+
OptModel.vNetworkInvest[p,ni,nf,cc].domain = UnitInterval
|
|
2395
|
+
OptModel.vNetworkInvPer[p,ni,nf,cc].domain = UnitInterval
|
|
2321
2396
|
nFixedVariables += 2
|
|
2322
2397
|
if mTEPES.pElecNetPeriodFin[ni,nf,cc] < p:
|
|
2323
2398
|
OptModel.vNetworkInvPer[p,ni,nf,cc].fix(0)
|
|
2399
|
+
OptModel.vNetworkInvPer[p,ni,nf,cc].domain = UnitInterval
|
|
2324
2400
|
nFixedVariables += 1
|
|
2325
2401
|
|
|
2326
2402
|
if mTEPES.pIndHydroTopology == 1:
|
|
@@ -2328,9 +2404,12 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
2328
2404
|
if mTEPES.pRsrPeriodIni[rc] > p:
|
|
2329
2405
|
OptModel.vReservoirInvest[p,rc].fix(0)
|
|
2330
2406
|
OptModel.vReservoirInvPer[p,rc].fix(0)
|
|
2407
|
+
OptModel.vReservoirInvest[p,rc].domain = UnitInterval
|
|
2408
|
+
OptModel.vReservoirInvPer[p,rc].domain = UnitInterval
|
|
2331
2409
|
nFixedVariables += 2
|
|
2332
2410
|
if mTEPES.pRsrPeriodFin[rc] < p:
|
|
2333
2411
|
OptModel.vReservoirInvPer[p,rc].fix(0)
|
|
2412
|
+
OptModel.vReservoirInvPer[p,rc].domain = UnitInterval
|
|
2334
2413
|
nFixedVariables += 1
|
|
2335
2414
|
|
|
2336
2415
|
if mTEPES.pIndHydrogen == 1:
|
|
@@ -2338,9 +2417,12 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
2338
2417
|
if mTEPES.pH2PipePeriodIni[ni,nf,cc] > p:
|
|
2339
2418
|
OptModel.vH2PipeInvest[p,ni,nf,cc].fix(0)
|
|
2340
2419
|
OptModel.vH2PipeInvPer[p,ni,nf,cc].fix(0)
|
|
2420
|
+
OptModel.vH2PipeInvest[p,ni,nf,cc].domain = UnitInterval
|
|
2421
|
+
OptModel.vH2PipeInvPer[p,ni,nf,cc].domain = UnitInterval
|
|
2341
2422
|
nFixedVariables += 2
|
|
2342
2423
|
if mTEPES.pH2PipePeriodFin[ni,nf,cc] < p:
|
|
2343
2424
|
OptModel.vH2PipeInvPer[p,ni,nf,cc].fix(0)
|
|
2425
|
+
OptModel.vH2PipeInvPer[p,ni,nf,cc].domain = UnitInterval
|
|
2344
2426
|
nFixedVariables += 1
|
|
2345
2427
|
|
|
2346
2428
|
if mTEPES.pIndHeat == 1:
|
|
@@ -2348,9 +2430,12 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
2348
2430
|
if mTEPES.pHeatPipePeriodIni[ni,nf,cc] > p:
|
|
2349
2431
|
OptModel.vHeatPipeInvest[p,ni,nf,cc].fix(0)
|
|
2350
2432
|
OptModel.vHeatPipeInvPer[p,ni,nf,cc].fix(0)
|
|
2433
|
+
OptModel.vHeatPipeInvest[p,ni,nf,cc].domain = UnitInterval
|
|
2434
|
+
OptModel.vHeatPipeInvPer[p,ni,nf,cc].domain = UnitInterval
|
|
2351
2435
|
nFixedVariables += 2
|
|
2352
2436
|
if mTEPES.pHeatPipePeriodFin[ni,nf,cc] < p:
|
|
2353
2437
|
OptModel.vHeatPipeInvPer[p,ni,nf,cc].fix(0)
|
|
2438
|
+
OptModel.vHeatPipeInvPer[p,ni,nf,cc].domain = UnitInterval
|
|
2354
2439
|
nFixedVariables += 1
|
|
2355
2440
|
|
|
2356
2441
|
# remove power plants and lines not installed in this period
|
|
@@ -2363,6 +2448,7 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
2363
2448
|
for p,sc,nr in mTEPES.psnr:
|
|
2364
2449
|
if nr not in mTEPES.eb and mTEPES.pElecGenPeriodIni[nr] > p:
|
|
2365
2450
|
OptModel.vMaxCommitment[p,sc,nr].fix(0)
|
|
2451
|
+
OptModel.vMaxCommitment[p,sc,nr].domain = UnitInterval
|
|
2366
2452
|
nFixedVariables += 1
|
|
2367
2453
|
for p,sc,n,nr in mTEPES.psnnr:
|
|
2368
2454
|
if nr not in mTEPES.eb and mTEPES.pElecGenPeriodIni[nr] > p:
|
|
@@ -2372,6 +2458,9 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
2372
2458
|
OptModel.vCommitment [p,sc,n,nr].fix(0 )
|
|
2373
2459
|
OptModel.vStartUp [p,sc,n,nr].fix(0 )
|
|
2374
2460
|
OptModel.vShutDown [p,sc,n,nr].fix(0 )
|
|
2461
|
+
OptModel.vCommitment [p,sc,n,nr].domain = UnitInterval
|
|
2462
|
+
OptModel.vStartUp [p,sc,n,nr].domain = UnitInterval
|
|
2463
|
+
OptModel.vShutDown [p,sc,n,nr].domain = UnitInterval
|
|
2375
2464
|
nFixedVariables += 6
|
|
2376
2465
|
|
|
2377
2466
|
for p,sc,n,es in mTEPES.psnes:
|
|
@@ -2408,22 +2497,29 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
2408
2497
|
nFixedInstallationsAndRetirements = AvoidForbiddenInstallationsAndRetirements(mTEPES, mTEPES)
|
|
2409
2498
|
nFixedVariables += nFixedInstallationsAndRetirements
|
|
2410
2499
|
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2500
|
+
for p,sc,n,ni,nf,cc in mTEPES.psnla:
|
|
2501
|
+
if (ni,nf,cc) not in mTEPES.lc and mTEPES.pElecNetPeriodIni[ni,nf,cc] > p:
|
|
2502
|
+
OptModel.vLineCommit [p,sc,n,ni,nf,cc].fix(0)
|
|
2503
|
+
OptModel.vLineOnState [p,sc,n,ni,nf,cc].fix(0)
|
|
2504
|
+
OptModel.vLineOffState[p,sc,n,ni,nf,cc].fix(0)
|
|
2505
|
+
OptModel.vLineCommit [p,sc,n,ni,nf,cc].domain = UnitInterval
|
|
2506
|
+
OptModel.vLineOnState [p,sc,n,ni,nf,cc].domain = UnitInterval
|
|
2507
|
+
OptModel.vLineOffState[p,sc,n,ni,nf,cc].domain = UnitInterval
|
|
2508
|
+
nFixedVariables += 3
|
|
2509
|
+
|
|
2510
|
+
[OptModel.vLineLosses [p,sc,n,ni,nf,cc].fix(0.0) for p,sc,n,ni,nf,cc in mTEPES.psnll if (ni,nf,cc) not in mTEPES.lc and mTEPES.pElecNetPeriodIni[ni,nf,cc] > p]
|
|
2511
|
+
nFixedVariables += sum( 1 for p,sc,n,ni,nf,cc in mTEPES.psnll if (ni,nf,cc) not in mTEPES.lc and mTEPES.pElecNetPeriodIni[ni,nf,cc] > p)
|
|
2416
2512
|
|
|
2417
|
-
[OptModel.
|
|
2418
|
-
nFixedVariables
|
|
2513
|
+
[OptModel.vFlowElec [p,sc,n,ni,nf,cc].fix(0.0) for p,sc,n,ni,nf,cc in mTEPES.psnla if (ni,nf,cc) not in mTEPES.lc and mTEPES.pElecNetPeriodIni[ni,nf,cc] > p]
|
|
2514
|
+
nFixedVariables += sum( 1 for p,sc,n,ni,nf,cc in mTEPES.psnla if (ni,nf,cc) not in mTEPES.lc and mTEPES.pElecNetPeriodIni[ni,nf,cc] > p)
|
|
2419
2515
|
|
|
2420
2516
|
if mTEPES.pIndHydrogen == 1:
|
|
2421
2517
|
[OptModel.vFlowH2 [p,sc,n,ni,nf,cc].fix(0.0) for p,sc,n,ni,nf,cc in mTEPES.psnpa if (ni,nf,cc) not in mTEPES.pc and mTEPES.pH2PipePeriodIni [ni,nf,cc] > p]
|
|
2422
|
-
nFixedVariables += sum(
|
|
2518
|
+
nFixedVariables += sum( 1 for p,sc,n,ni,nf,cc in mTEPES.psnpa if (ni,nf,cc) not in mTEPES.pc and mTEPES.pH2PipePeriodIni [ni,nf,cc] > p)
|
|
2423
2519
|
|
|
2424
2520
|
if mTEPES.pIndHeat == 1:
|
|
2425
2521
|
[OptModel.vFlowHeat[p,sc,n,ni,nf,cc].fix(0.0) for p,sc,n,ni,nf,cc in mTEPES.psnha if (ni,nf,cc) not in mTEPES.hc and mTEPES.pHeatPipePeriodIni[ni,nf,cc] > p]
|
|
2426
|
-
nFixedVariables += sum(
|
|
2522
|
+
nFixedVariables += sum( 1 for p,sc,n,ni,nf,cc in mTEPES.psnha if (ni,nf,cc) not in mTEPES.hc and mTEPES.pHeatPipePeriodIni[ni,nf,cc] > p)
|
|
2427
2523
|
|
|
2428
2524
|
# tolerance to consider 0 an investment decision
|
|
2429
2525
|
pEpsilon = 1e-4
|
|
@@ -2442,31 +2538,31 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
2442
2538
|
None: Changes are performed directly onto the model object.
|
|
2443
2539
|
'''
|
|
2444
2540
|
for p,eb in mTEPES.peb:
|
|
2445
|
-
if mTEPES.pGenLoInvest[ eb
|
|
2446
|
-
mTEPES.pGenLoInvest[ eb
|
|
2447
|
-
if mTEPES.pGenUpInvest[ eb
|
|
2448
|
-
mTEPES.pGenUpInvest[ eb
|
|
2449
|
-
if mTEPES.pGenLoInvest[ eb
|
|
2450
|
-
mTEPES.pGenLoInvest[ eb
|
|
2451
|
-
if mTEPES.pGenUpInvest[ eb
|
|
2452
|
-
mTEPES.pGenUpInvest[ eb
|
|
2453
|
-
if mTEPES.pGenLoInvest[ eb
|
|
2454
|
-
mTEPES.pGenLoInvest[ eb
|
|
2455
|
-
[OptModel.vGenerationInvest[p,eb
|
|
2456
|
-
[OptModel.vGenerationInvest[p,eb
|
|
2541
|
+
if mTEPES.pGenLoInvest[ eb]() < pEpsilon:
|
|
2542
|
+
mTEPES.pGenLoInvest[ eb] = 0
|
|
2543
|
+
if mTEPES.pGenUpInvest[ eb]() < pEpsilon:
|
|
2544
|
+
mTEPES.pGenUpInvest[ eb] = 0
|
|
2545
|
+
if mTEPES.pGenLoInvest[ eb]() > 1.0 - pEpsilon:
|
|
2546
|
+
mTEPES.pGenLoInvest[ eb] = 1
|
|
2547
|
+
if mTEPES.pGenUpInvest[ eb]() > 1.0 - pEpsilon:
|
|
2548
|
+
mTEPES.pGenUpInvest[ eb] = 1
|
|
2549
|
+
if mTEPES.pGenLoInvest[ eb]() > mTEPES.pGenUpInvest[eb]():
|
|
2550
|
+
mTEPES.pGenLoInvest[ eb] = mTEPES.pGenUpInvest[eb]()
|
|
2551
|
+
[OptModel.vGenerationInvest[p,eb].setlb(mTEPES.pGenLoInvest[eb]()) for p,eb in mTEPES.peb]
|
|
2552
|
+
[OptModel.vGenerationInvest[p,eb].setub(mTEPES.pGenUpInvest[eb]()) for p,eb in mTEPES.peb]
|
|
2457
2553
|
for p,gd in mTEPES.pgd:
|
|
2458
|
-
if mTEPES.pGenLoRetire[ gd
|
|
2459
|
-
mTEPES.pGenLoRetire[ gd
|
|
2460
|
-
if mTEPES.pGenUpRetire[ gd
|
|
2461
|
-
mTEPES.pGenUpRetire[ gd
|
|
2462
|
-
if mTEPES.pGenLoRetire[ gd
|
|
2463
|
-
mTEPES.pGenLoRetire[ gd
|
|
2464
|
-
if mTEPES.pGenUpRetire[ gd
|
|
2465
|
-
mTEPES.pGenUpRetire[ gd
|
|
2466
|
-
if mTEPES.pGenLoRetire[ gd
|
|
2467
|
-
mTEPES.pGenLoRetire[ gd
|
|
2468
|
-
[OptModel.vGenerationRetire[p,gd
|
|
2469
|
-
[OptModel.vGenerationRetire[p,gd
|
|
2554
|
+
if mTEPES.pGenLoRetire[ gd]() < pEpsilon:
|
|
2555
|
+
mTEPES.pGenLoRetire[ gd] = 0
|
|
2556
|
+
if mTEPES.pGenUpRetire[ gd]() < pEpsilon:
|
|
2557
|
+
mTEPES.pGenUpRetire[ gd] = 0
|
|
2558
|
+
if mTEPES.pGenLoRetire[ gd]() > 1.0 - pEpsilon:
|
|
2559
|
+
mTEPES.pGenLoRetire[ gd] = 1
|
|
2560
|
+
if mTEPES.pGenUpRetire[ gd]() > 1.0 - pEpsilon:
|
|
2561
|
+
mTEPES.pGenUpRetire[ gd] = 1
|
|
2562
|
+
if mTEPES.pGenLoRetire[ gd]() > mTEPES.pGenUpRetire[gd]():
|
|
2563
|
+
mTEPES.pGenLoRetire[ gd] = mTEPES.pGenUpRetire[gd]()
|
|
2564
|
+
[OptModel.vGenerationRetire[p,gd].setlb(mTEPES.pGenLoRetire[gd]()) for p,gd in mTEPES.pgd]
|
|
2565
|
+
[OptModel.vGenerationRetire[p,gd].setub(mTEPES.pGenUpRetire[gd]()) for p,gd in mTEPES.pgd]
|
|
2470
2566
|
for p,ni,nf,cc in mTEPES.plc:
|
|
2471
2567
|
if mTEPES.pNetLoInvest[ ni,nf,cc]() < pEpsilon:
|
|
2472
2568
|
mTEPES.pNetLoInvest[ ni,nf,cc] = 0
|
|
@@ -2483,18 +2579,18 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
2483
2579
|
|
|
2484
2580
|
if mTEPES.pIndHydroTopology == 1:
|
|
2485
2581
|
for p,rc in mTEPES.prc:
|
|
2486
|
-
if mTEPES.pRsrLoInvest[ rc
|
|
2487
|
-
mTEPES.pRsrLoInvest[ rc
|
|
2488
|
-
if mTEPES.pRsrUpInvest[ rc
|
|
2489
|
-
mTEPES.pRsrUpInvest[ rc
|
|
2490
|
-
if mTEPES.pRsrLoInvest[ rc
|
|
2491
|
-
mTEPES.pRsrLoInvest[ rc
|
|
2492
|
-
if mTEPES.pRsrUpInvest[ rc
|
|
2493
|
-
mTEPES.pRsrUpInvest[ rc
|
|
2494
|
-
if mTEPES.pRsrLoInvest[ rc
|
|
2495
|
-
mTEPES.pRsrLoInvest[ rc
|
|
2496
|
-
[OptModel.vReservoirInvest [p,rc
|
|
2497
|
-
[OptModel.vReservoirInvest [p,rc
|
|
2582
|
+
if mTEPES.pRsrLoInvest[ rc]() < pEpsilon:
|
|
2583
|
+
mTEPES.pRsrLoInvest[ rc] = 0
|
|
2584
|
+
if mTEPES.pRsrUpInvest[ rc]() < pEpsilon:
|
|
2585
|
+
mTEPES.pRsrUpInvest[ rc] = 0
|
|
2586
|
+
if mTEPES.pRsrLoInvest[ rc]() > 1.0 - pEpsilon:
|
|
2587
|
+
mTEPES.pRsrLoInvest[ rc] = 1
|
|
2588
|
+
if mTEPES.pRsrUpInvest[ rc]() > 1.0 - pEpsilon:
|
|
2589
|
+
mTEPES.pRsrUpInvest[ rc] = 1
|
|
2590
|
+
if mTEPES.pRsrLoInvest[ rc]() > mTEPES.pRsrUpInvest[rc]():
|
|
2591
|
+
mTEPES.pRsrLoInvest[ rc] = mTEPES.pRsrUpInvest[rc]()
|
|
2592
|
+
[OptModel.vReservoirInvest [p,rc].setlb(mTEPES.pRsrLoInvest[rc]()) for p,rc in mTEPES.prc]
|
|
2593
|
+
[OptModel.vReservoirInvest [p,rc].setub(mTEPES.pRsrUpInvest[rc]()) for p,rc in mTEPES.prc]
|
|
2498
2594
|
|
|
2499
2595
|
if mTEPES.pIndHydrogen == 1:
|
|
2500
2596
|
for p,ni,nf,cc in mTEPES.ppc:
|
|
@@ -2549,16 +2645,20 @@ def SettingUpVariables(OptModel, mTEPES):
|
|
|
2549
2645
|
raise ValueError('### No active stages in the case study' )
|
|
2550
2646
|
|
|
2551
2647
|
# detecting infeasibility: sum of scenario probabilities must be 1 in each period
|
|
2552
|
-
#
|
|
2553
|
-
|
|
2554
|
-
|
|
2648
|
+
# tolerance to consider 0 the difference between parameters
|
|
2649
|
+
pEpsilon = 1e-6
|
|
2650
|
+
for p in mTEPES.p:
|
|
2651
|
+
if abs(sum(mTEPES.pScenProb[p,sc]() for sc in mTEPES.sc if (p,sc) in mTEPES.ps)-1.0) > pEpsilon:
|
|
2652
|
+
raise ValueError('### Sum of scenario probabilities different from 1 in period ', p)
|
|
2555
2653
|
|
|
2556
2654
|
for es in mTEPES.es:
|
|
2557
|
-
# detecting infeasibility: total min ESS output greater than total inflows, total max ESS charge lower than total outflows
|
|
2558
|
-
if sum(mTEPES.pMinPowerElec[p,sc,n,es] for p,sc,n in mTEPES.psn if (p,es) in mTEPES.pes) - sum(mTEPES.pEnergyInflows [p,sc,n,es]() for p,sc,n in mTEPES.psn if (p,es) in mTEPES.pes) >
|
|
2655
|
+
# detecting infeasibility: total min ESS output greater than total inflows, total max ESS charge lower than total outflows, or no storage capacity for charging
|
|
2656
|
+
if sum(mTEPES.pMinPowerElec[p,sc,n,es] for p,sc,n in mTEPES.psn if (p,es) in mTEPES.pes) - sum(mTEPES.pEnergyInflows [p,sc,n,es]() for p,sc,n in mTEPES.psn if (p,es) in mTEPES.pes) > 0.0:
|
|
2559
2657
|
raise ValueError('### Total minimum output greater than total inflows for ESS unit ', es, ' by ', sum(mTEPES.pMinPowerElec[p,sc,n,es] for p,sc,n in mTEPES.psn if (p,es) in mTEPES.pes) - sum(mTEPES.pEnergyInflows [p,sc,n,es]() for p,sc,n in mTEPES.psn if (p,es) in mTEPES.pes), ' GWh')
|
|
2560
|
-
if sum(mTEPES.pMaxCharge [p,sc,n,es] for p,sc,n in mTEPES.psn if (p,es) in mTEPES.pes) - sum(mTEPES.pEnergyOutflows[p,sc,n,es]() for p,sc,n in mTEPES.psn if (p,es) in mTEPES.pes) <
|
|
2658
|
+
if sum(mTEPES.pMaxCharge [p,sc,n,es] for p,sc,n in mTEPES.psn if (p,es) in mTEPES.pes) - sum(mTEPES.pEnergyOutflows[p,sc,n,es]() for p,sc,n in mTEPES.psn if (p,es) in mTEPES.pes) < 0.0:
|
|
2561
2659
|
raise ValueError('### Total maximum charge lower than total outflows for ESS unit ', es, ' by ', sum(mTEPES.pMaxCharge [p,sc,n,es] for p,sc,n in mTEPES.psn if (p,es) in mTEPES.pes) - sum(mTEPES.pEnergyOutflows[p,sc,n,es]() for p,sc,n in mTEPES.psn if (p,es) in mTEPES.pes), ' GWh')
|
|
2660
|
+
if max(mTEPES.pMaxCharge[p,sc,n,es] for p,sc,n in mTEPES.psn if (p,es) in mTEPES.pes) and max(mTEPES.pMaxPowerElec[p,sc,n,es] for p,sc,n in mTEPES.psn if (p,es) in mTEPES.pes) and max(mTEPES.pMaxStorage[p,sc,n,es] for p,sc,n in mTEPES.psn if (p,es) in mTEPES.pes) == 0.0:
|
|
2661
|
+
raise ValueError('### This ESS unit has no storage capacity for charging ', es, ' ', sum(mTEPES.pMaxCharge [p,sc,n,es] for p,sc,n in mTEPES.psn if (p,es) in mTEPES.pes), ' MW ', sum(mTEPES.pMaxStorage [p,sc,n,es] for p,sc,n in mTEPES.psn if (p,es) in mTEPES.pes), ' GWh')
|
|
2562
2662
|
|
|
2563
2663
|
# detect inventory infeasibility
|
|
2564
2664
|
for p,sc,n,es in mTEPES.ps*mTEPES.nesc:
|