openTEPES 4.18.2__py3-none-any.whl → 4.18.3__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/9n/oT_Data_RESEnergy_9n.csv +1 -1
- openTEPES/9n/oT_Data_ReserveMargin_9n.csv +1 -1
- openTEPES/__init__.py +1 -1
- openTEPES/openTEPES.py +11 -5
- openTEPES/openTEPES_InputData.py +117 -93
- openTEPES/openTEPES_Main.py +4 -3
- openTEPES/openTEPES_ModelFormulation.py +54 -45
- openTEPES/openTEPES_OutputResults.py +178 -149
- openTEPES/openTEPES_ProblemSolving.py +4 -5
- {opentepes-4.18.2.dist-info → opentepes-4.18.3.dist-info}/METADATA +6 -3
- {opentepes-4.18.2.dist-info → opentepes-4.18.3.dist-info}/RECORD +14 -14
- {opentepes-4.18.2.dist-info → opentepes-4.18.3.dist-info}/LICENSE +0 -0
- {opentepes-4.18.2.dist-info → opentepes-4.18.3.dist-info}/WHEEL +0 -0
- {opentepes-4.18.2.dist-info → opentepes-4.18.3.dist-info}/entry_points.txt +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
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) - March 18, 2025
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import time
|
|
@@ -170,6 +170,14 @@ def GenerationOperationModelFormulationObjFunct(OptModel, mTEPES, pIndLogConsole
|
|
|
170
170
|
return Constraint.Skip
|
|
171
171
|
setattr(OptModel, f'eTotalECost_{p}_{sc}_{st}', Constraint(mTEPES.n, rule=eTotalECost, doc='system emission cost [MEUR]'))
|
|
172
172
|
|
|
173
|
+
def eTotalEmissionArea(OptModel,n,ar):
|
|
174
|
+
if sum(mTEPES.pEmissionRate[g] for g in mTEPES.g if (ar, g) in mTEPES.a2g and (p, g) in mTEPES.pg):
|
|
175
|
+
return OptModel.vTotalEmissionArea[p,sc,n,ar] == (sum(mTEPES.pLoadLevelDuration[p,sc,n]() * mTEPES.pEmissionRate[nr] * 1e-3 * OptModel.vTotalOutput [p,sc,n,nr] for nr in mTEPES.nr if (ar,nr) in mTEPES.a2g and (p,nr) in mTEPES.pnr) #1e-3 to change from tCO2/MWh to MtCO2/GWh
|
|
176
|
+
+ sum(mTEPES.pLoadLevelDuration[p,sc,n]() * mTEPES.pEmissionRate[bo] * 1e-3 * OptModel.vTotalOutputHeat[p,sc,n,bo] for bo in mTEPES.bo if (ar,bo) in mTEPES.a2g and (p,bo) in mTEPES.pbo)) #1e-3 to change from tCO2/MWh to MtCO2/GWh
|
|
177
|
+
else:
|
|
178
|
+
return Constraint.Skip
|
|
179
|
+
setattr(OptModel, f'eTotalEmissionArea_{p}_{sc}_{st}', Constraint(mTEPES.n, mTEPES.ar, rule=eTotalEmissionArea, doc='area total emission [MtCO2 eq]'))
|
|
180
|
+
|
|
173
181
|
def eTotalECostArea(OptModel,n,ar):
|
|
174
182
|
if sum(mTEPES.pEmissionVarCost[p,sc,n,g] for g in mTEPES.g if (ar,g) in mTEPES.a2g and (p,g) in mTEPES.pg):
|
|
175
183
|
return OptModel.vTotalECostArea[p,sc,n,ar] == (sum(mTEPES.pLoadLevelDuration[p,sc,n]() * mTEPES.pEmissionVarCost[p,sc,n,nr] * OptModel.vTotalOutput [p,sc,n,nr] for nr in mTEPES.nr if (ar,nr) in mTEPES.a2g and (p,nr) in mTEPES.pnr)
|
|
@@ -207,7 +215,7 @@ def GenerationOperationModelFormulationInvestment(OptModel, mTEPES, pIndLogConso
|
|
|
207
215
|
StartTime = time.time()
|
|
208
216
|
|
|
209
217
|
def eInstallGenComm(OptModel,n,gc):
|
|
210
|
-
if gc in mTEPES.nr and gc not in mTEPES.eh and gc not in mTEPES.bc and mTEPES.pMustRun[gc] == 0 and (mTEPES.pMinPowerElec[p,sc,n,gc]
|
|
218
|
+
if gc in mTEPES.nr and gc not in mTEPES.eh and gc not in mTEPES.bc and mTEPES.pMustRun[gc] == 0 and (mTEPES.pMinPowerElec[p,sc,n,gc] or mTEPES.pConstantVarCost[p,sc,n,gc]):
|
|
211
219
|
return OptModel.vCommitment[p,sc,n,gc] <= OptModel.vGenerationInvest[p,gc]
|
|
212
220
|
else:
|
|
213
221
|
return Constraint.Skip
|
|
@@ -267,7 +275,7 @@ def GenerationOperationModelFormulationInvestment(OptModel, mTEPES, pIndLogConso
|
|
|
267
275
|
|
|
268
276
|
def eUninstallGenComm(OptModel,n,gd):
|
|
269
277
|
if (p,gd) in mTEPES.pgd:
|
|
270
|
-
if gd in mTEPES.nr and gd not in mTEPES.eh and mTEPES.pMustRun[gd] == 0 and (mTEPES.pMinPowerElec[p,sc,n,gd]
|
|
278
|
+
if gd in mTEPES.nr and gd not in mTEPES.eh and mTEPES.pMustRun[gd] == 0 and (mTEPES.pMinPowerElec[p,sc,n,gd] or mTEPES.pConstantVarCost[p,sc,n,gd]):
|
|
271
279
|
return OptModel.vCommitment[p,sc,n,gd] <= 1 - OptModel.vGenerationRetire[p,gd]
|
|
272
280
|
else:
|
|
273
281
|
return Constraint.Skip
|
|
@@ -319,8 +327,9 @@ def GenerationOperationModelFormulationInvestment(OptModel, mTEPES, pIndLogConso
|
|
|
319
327
|
print('eAdeqReserveMarginHeat... ', len(getattr(OptModel, f'eAdequacyReserveMarginHeat_{p}_{sc}_{st}')), ' rows')
|
|
320
328
|
|
|
321
329
|
def eMaxSystemEmission(OptModel,ar):
|
|
322
|
-
if mTEPES.pEmission[p,ar] < math.inf
|
|
323
|
-
|
|
330
|
+
if mTEPES.pEmission[p,ar] < math.inf and sum(mTEPES.pEmissionRate[nr] for nr in mTEPES.nr if (ar,nr) in mTEPES.a2g) and st == mTEPES.Last_st:
|
|
331
|
+
# There is an emission limit, there are generators with emissions in the Area and it is the last stage
|
|
332
|
+
return sum(OptModel.vTotalEmissionArea[p,sc,na,ar] for na in mTEPES.na) <= mTEPES.pEmission[p,ar]
|
|
324
333
|
else:
|
|
325
334
|
return Constraint.Skip
|
|
326
335
|
setattr(OptModel, f'eMaxSystemEmission_{p}_{sc}_{st}', Constraint(mTEPES.ar, rule=eMaxSystemEmission, doc='maximum CO2 emission [tCO2]'))
|
|
@@ -440,7 +449,7 @@ def GenerationOperationModelFormulationDemand(OptModel, mTEPES, pIndLogConsole,
|
|
|
440
449
|
print('eReserveMaxRatioDwUp ... ', len(getattr(OptModel, f'eReserveMaxRatioDwUp_{p}_{sc}_{st}')), ' rows')
|
|
441
450
|
|
|
442
451
|
def eRsrvMinRatioDwUpESS(OptModel,n,eh):
|
|
443
|
-
if mTEPES.pMinRatioDwUp
|
|
452
|
+
if mTEPES.pMinRatioDwUp and sum(mTEPES.pOperReserveUp[p,sc,n,ar] for ar in a2e[eh]) and sum(mTEPES.pOperReserveDw[p,sc,n,ar] for ar in a2e[eh]) and mTEPES.pMaxPower2ndBlock[p,sc,n,eh] and mTEPES.pIndOperReserve[eh] == 0:
|
|
444
453
|
return OptModel.vESSReserveDown[p,sc,n,eh] >= OptModel.vESSReserveUp[p,sc,n,eh] * mTEPES.pMinRatioDwUp
|
|
445
454
|
else:
|
|
446
455
|
return Constraint.Skip
|
|
@@ -461,7 +470,7 @@ def GenerationOperationModelFormulationDemand(OptModel, mTEPES, pIndLogConsole,
|
|
|
461
470
|
|
|
462
471
|
def eReserveUpIfEnergy(OptModel,n,es):
|
|
463
472
|
if mTEPES.pIndOperReserve[es] == 0 and (p,es) in mTEPES.pes:
|
|
464
|
-
if sum(mTEPES.pOperReserveUp[p,sc,n,ar] for ar in a2e[es]) and mTEPES.pMaxPower2ndBlock [p,sc,n,es] and mTEPES.pDuration[p,sc,n]():
|
|
473
|
+
if sum(mTEPES.pOperReserveUp[p,sc,n,ar] for ar in a2e[es]) and (mTEPES.pTotalMaxCharge[es] or mTEPES.pTotalEnergyInflows[es]) and mTEPES.pMaxPower2ndBlock [p,sc,n,es] and mTEPES.pDuration[p,sc,n]():
|
|
465
474
|
return OptModel.vReserveUp [p,sc,n,es] <= OptModel.vESSInventory[p,sc,n,es] / mTEPES.pDuration[p,sc,n]()
|
|
466
475
|
else:
|
|
467
476
|
return Constraint.Skip
|
|
@@ -474,7 +483,7 @@ def GenerationOperationModelFormulationDemand(OptModel, mTEPES, pIndLogConsole,
|
|
|
474
483
|
|
|
475
484
|
def eReserveDwIfEnergy(OptModel,n,es):
|
|
476
485
|
if mTEPES.pIndOperReserve[es] == 0 and (p,es) in mTEPES.pes:
|
|
477
|
-
if sum(mTEPES.pOperReserveDw[p,sc,n,ar] for ar in a2e[es]) and mTEPES.pMaxPower2ndBlock [p,sc,n,es] and mTEPES.pDuration[p,sc,n]():
|
|
486
|
+
if sum(mTEPES.pOperReserveDw[p,sc,n,ar] for ar in a2e[es]) and (mTEPES.pTotalMaxCharge[es] or mTEPES.pTotalEnergyInflows[es]) and mTEPES.pMaxPower2ndBlock [p,sc,n,es] and mTEPES.pDuration[p,sc,n]():
|
|
478
487
|
return OptModel.vReserveDown[p,sc,n,es] <= (mTEPES.pMaxStorage[p,sc,n,es] - OptModel.vESSInventory[p,sc,n,es]) / mTEPES.pDuration[p,sc,n]()
|
|
479
488
|
else:
|
|
480
489
|
return Constraint.Skip
|
|
@@ -487,7 +496,7 @@ def GenerationOperationModelFormulationDemand(OptModel, mTEPES, pIndLogConsole,
|
|
|
487
496
|
|
|
488
497
|
def eESSReserveUpIfEnergy(OptModel,n,es):
|
|
489
498
|
if mTEPES.pIndOperReserve[es] == 0 and (p,es) in mTEPES.pes:
|
|
490
|
-
if sum(mTEPES.pOperReserveUp[p,sc,n,ar] for ar in a2e[es]) and mTEPES.pMaxCharge2ndBlock[p,sc,n,es] and mTEPES.pDuration[p,sc,n]():
|
|
499
|
+
if sum(mTEPES.pOperReserveUp[p,sc,n,ar] for ar in a2e[es]) and (mTEPES.pTotalMaxCharge[es] or mTEPES.pTotalEnergyInflows[es]) and mTEPES.pMaxCharge2ndBlock[p,sc,n,es] and mTEPES.pDuration[p,sc,n]():
|
|
491
500
|
return OptModel.vESSReserveUp [p,sc,n,es] <= (mTEPES.pMaxStorage[p,sc,n,es] - OptModel.vESSInventory[p,sc,n,es]) / mTEPES.pDuration[p,sc,n]()
|
|
492
501
|
else:
|
|
493
502
|
return Constraint.Skip
|
|
@@ -500,7 +509,7 @@ def GenerationOperationModelFormulationDemand(OptModel, mTEPES, pIndLogConsole,
|
|
|
500
509
|
|
|
501
510
|
def eESSReserveDwIfEnergy(OptModel,n,es):
|
|
502
511
|
if mTEPES.pIndOperReserve[es] == 0 and (p,es) in mTEPES.pes:
|
|
503
|
-
if sum(mTEPES.pOperReserveDw[p,sc,n,ar] for ar in a2e[es]) and mTEPES.pMaxCharge2ndBlock[p,sc,n,es] and mTEPES.pDuration[p,sc,n]():
|
|
512
|
+
if sum(mTEPES.pOperReserveDw[p,sc,n,ar] for ar in a2e[es]) and (mTEPES.pTotalMaxCharge[es] or mTEPES.pTotalEnergyInflows[es]) and mTEPES.pMaxCharge2ndBlock[p,sc,n,es] and mTEPES.pDuration[p,sc,n]():
|
|
504
513
|
return OptModel.vESSReserveDown[p,sc,n,es] <= OptModel.vESSInventory[p,sc,n,es] / mTEPES.pDuration[p,sc,n]()
|
|
505
514
|
else:
|
|
506
515
|
return Constraint.Skip
|
|
@@ -579,7 +588,7 @@ def GenerationOperationModelFormulationStorage(OptModel, mTEPES, pIndLogConsole,
|
|
|
579
588
|
print('eInflows2Comm ... ', len(getattr(OptModel, f'eInflows2Comm_{p}_{sc}_{st}')), ' rows')
|
|
580
589
|
|
|
581
590
|
def eESSInventory(OptModel,n,es):
|
|
582
|
-
if (p,es) in mTEPES.pes:
|
|
591
|
+
if (p,es) in mTEPES.pes and (mTEPES.pTotalMaxCharge[es] or mTEPES.pTotalEnergyInflows[es]):
|
|
583
592
|
if (p,sc,st,n) in mTEPES.s2n and mTEPES.n.ord(n) == mTEPES.pStorageTimeStep[es]:
|
|
584
593
|
if es not in mTEPES.ec:
|
|
585
594
|
return mTEPES.pIniInventory[p,sc,n,es]() + sum(mTEPES.pDuration[p,sc,n2]()*(mTEPES.pEnergyInflows[p,sc,n2,es]() - OptModel.vEnergyOutflows[p,sc,n2,es] - OptModel.vTotalOutput[p,sc,n2,es] + mTEPES.pEfficiency[es]*OptModel.vESSTotalCharge[p,sc,n2,es]) for n2 in list(mTEPES.n2)[mTEPES.n.ord(n)-mTEPES.pStorageTimeStep[es]:mTEPES.n.ord(n)]) == OptModel.vESSInventory[p,sc,n,es] + OptModel.vESSSpillage[p,sc,n,es]
|
|
@@ -666,7 +675,7 @@ def GenerationOperationModelFormulationStorage(OptModel, mTEPES, pIndLogConsole,
|
|
|
666
675
|
if (p,eh) in mTEPES.peh:
|
|
667
676
|
if mTEPES.pMaxPower2ndBlock [p,sc,n,eh] and mTEPES.pMaxCharge2ndBlock[p,sc,n,eh]:
|
|
668
677
|
return ((OptModel.vOutput2ndBlock[p,sc,n,eh] + mTEPES.pUpReserveActivation * OptModel.vReserveUp [p,sc,n,eh]) / mTEPES.pMaxPower2ndBlock [p,sc,n,eh] +
|
|
669
|
-
(OptModel.vCharge2ndBlock[p,sc,n,eh] + mTEPES.
|
|
678
|
+
(OptModel.vCharge2ndBlock[p,sc,n,eh] + mTEPES.pDwReserveActivation * OptModel.vESSReserveDown[p,sc,n,eh]) / mTEPES.pMaxCharge2ndBlock[p,sc,n,eh] <= 1.0)
|
|
670
679
|
else:
|
|
671
680
|
return Constraint.Skip
|
|
672
681
|
else:
|
|
@@ -680,9 +689,9 @@ def GenerationOperationModelFormulationStorage(OptModel, mTEPES, pIndLogConsole,
|
|
|
680
689
|
if (p,eh) in mTEPES.peh:
|
|
681
690
|
if mTEPES.pMaxCharge[p,sc,n,eh] and mTEPES.pMaxCharge2ndBlock[p,sc,n,eh]:
|
|
682
691
|
if mTEPES.pMinCharge[p,sc,n,eh] == 0.0:
|
|
683
|
-
return OptModel.vESSTotalCharge[p,sc,n,eh] == OptModel.vCharge2ndBlock[p,sc,n,eh] + mTEPES.
|
|
692
|
+
return OptModel.vESSTotalCharge[p,sc,n,eh] == OptModel.vCharge2ndBlock[p,sc,n,eh] + mTEPES.pDwReserveActivation * OptModel.vESSReserveDown[p,sc,n,eh] - mTEPES.pUpReserveActivation * OptModel.vESSReserveUp[p,sc,n,eh]
|
|
684
693
|
else:
|
|
685
|
-
return OptModel.vESSTotalCharge[p,sc,n,eh] / mTEPES.pMinCharge[p,sc,n,eh] == 1.0 + (OptModel.vCharge2ndBlock[p,sc,n,eh] + mTEPES.
|
|
694
|
+
return OptModel.vESSTotalCharge[p,sc,n,eh] / mTEPES.pMinCharge[p,sc,n,eh] == 1.0 + (OptModel.vCharge2ndBlock[p,sc,n,eh] + mTEPES.pDwReserveActivation * OptModel.vESSReserveDown[p,sc,n,eh] - mTEPES.pUpReserveActivation * OptModel.vESSReserveUp[p,sc,n,eh]) / mTEPES.pMinCharge[p,sc,n,eh]
|
|
686
695
|
else:
|
|
687
696
|
return Constraint.Skip
|
|
688
697
|
else:
|
|
@@ -832,14 +841,14 @@ def GenerationOperationModelFormulationReservoir(OptModel, mTEPES, pIndLogConsol
|
|
|
832
841
|
if (p,rs) in mTEPES.prs and sum(1 for h in mTEPES.h if (rs,h) in mTEPES.r2h or (h,rs) in mTEPES.h2r or (rs,h) in mTEPES.r2p or (h,rs) in mTEPES.p2r):
|
|
833
842
|
if (p,sc,st,n) in mTEPES.s2n and mTEPES.n.ord(n) == mTEPES.pReservoirTimeStep[rs]:
|
|
834
843
|
if rs not in mTEPES.rn:
|
|
835
|
-
return (mTEPES.pIniVolume[p,sc,n,rs]() + sum(mTEPES.pDuration[p,sc,n2]()*(mTEPES.pHydroInflows[p,sc,n2,rs]()*0.0036 - OptModel.vHydroOutflows[p,sc,n2,rs]*0.0036 - sum(OptModel.vTotalOutput[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (rs,h) in mTEPES.r2h) + sum(OptModel.vTotalOutput[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (h,rs) in mTEPES.h2r)
|
|
844
|
+
return (mTEPES.pIniVolume[p,sc,n,rs]() + sum(mTEPES.pDuration[p,sc,n2]()*(mTEPES.pHydroInflows[p,sc,n2,rs]()*0.0036 - OptModel.vHydroOutflows[p,sc,n2,rs]*0.0036 - sum(OptModel.vTotalOutput[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (rs,h) in mTEPES.r2h) + sum(OptModel.vTotalOutput[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (h,rs) in mTEPES.h2r) - sum(mTEPES.pEfficiency[h]*OptModel.vESSTotalCharge[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (rs,h) in mTEPES.r2p) + sum(mTEPES.pEfficiency[h]*OptModel.vESSTotalCharge[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (h,rs) in mTEPES.p2r)) for n2 in list(mTEPES.n2)[mTEPES.n.ord(n)-mTEPES.pReservoirTimeStep[rs]:mTEPES.n.ord(n)]) == OptModel.vReservoirVolume[p,sc,n,rs] + OptModel.vReservoirSpillage[p,sc,n,rs] - sum(OptModel.vReservoirSpillage[p,sc,n,rsr] for rsr in mTEPES.rs if (rsr,rs) in mTEPES.r2r))
|
|
836
845
|
else:
|
|
837
|
-
return (OptModel.vIniVolume[p,sc,n,rs] + sum(mTEPES.pDuration[p,sc,n2]()*(OptModel.vHydroInflows[p,sc,n2,rs]*0.0036 - OptModel.vHydroOutflows[p,sc,n2,rs]*0.0036 - sum(OptModel.vTotalOutput[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (rs,h) in mTEPES.r2h) + sum(OptModel.vTotalOutput[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (h,rs) in mTEPES.h2r)
|
|
846
|
+
return (OptModel.vIniVolume[p,sc,n,rs] + sum(mTEPES.pDuration[p,sc,n2]()*(OptModel.vHydroInflows[p,sc,n2,rs]*0.0036 - OptModel.vHydroOutflows[p,sc,n2,rs]*0.0036 - sum(OptModel.vTotalOutput[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (rs,h) in mTEPES.r2h) + sum(OptModel.vTotalOutput[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (h,rs) in mTEPES.h2r) - sum(mTEPES.pEfficiency[h]*OptModel.vESSTotalCharge[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (rs,h) in mTEPES.r2p) + sum(mTEPES.pEfficiency[h]*OptModel.vESSTotalCharge[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (h,rs) in mTEPES.p2r)) for n2 in list(mTEPES.n2)[mTEPES.n.ord(n)-mTEPES.pReservoirTimeStep[rs]:mTEPES.n.ord(n)]) == OptModel.vReservoirVolume[p,sc,n,rs] + OptModel.vReservoirSpillage[p,sc,n,rs] - sum(OptModel.vReservoirSpillage[p,sc,n,rsr] for rsr in mTEPES.rs if (rsr,rs) in mTEPES.r2r))
|
|
838
847
|
elif (p,sc,st,n) in mTEPES.s2n and mTEPES.n.ord(n) > mTEPES.pReservoirTimeStep[rs]:
|
|
839
848
|
if rs not in mTEPES.rn:
|
|
840
|
-
return (OptModel.vReservoirVolume[p,sc,mTEPES.n.prev(n,mTEPES.pReservoirTimeStep[rs]),rs] + sum(mTEPES.pDuration[p,sc,n2]()*(mTEPES.pHydroInflows[p,sc,n2,rs]()*0.0036 - OptModel.vHydroOutflows[p,sc,n2,rs]*0.0036 - sum(OptModel.vTotalOutput[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (rs,h) in mTEPES.r2h) + sum(OptModel.vTotalOutput[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (h,rs) in mTEPES.h2r)
|
|
849
|
+
return (OptModel.vReservoirVolume[p,sc,mTEPES.n.prev(n,mTEPES.pReservoirTimeStep[rs]),rs] + sum(mTEPES.pDuration[p,sc,n2]()*(mTEPES.pHydroInflows[p,sc,n2,rs]()*0.0036 - OptModel.vHydroOutflows[p,sc,n2,rs]*0.0036 - sum(OptModel.vTotalOutput[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (rs,h) in mTEPES.r2h) + sum(OptModel.vTotalOutput[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (h,rs) in mTEPES.h2r) - sum(mTEPES.pEfficiency[h]*OptModel.vESSTotalCharge[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (rs,h) in mTEPES.r2p) + sum(mTEPES.pEfficiency[h]*OptModel.vESSTotalCharge[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (h,rs) in mTEPES.p2r)) for n2 in list(mTEPES.n2)[mTEPES.n.ord(n)-mTEPES.pReservoirTimeStep[rs]:mTEPES.n.ord(n)]) == OptModel.vReservoirVolume[p,sc,n,rs] + OptModel.vReservoirSpillage[p,sc,n,rs] - sum(OptModel.vReservoirSpillage[p,sc,n,rsr] for rsr in mTEPES.rs if (rsr,rs) in mTEPES.r2r))
|
|
841
850
|
else:
|
|
842
|
-
return (OptModel.vReservoirVolume[p,sc,mTEPES.n.prev(n,mTEPES.pReservoirTimeStep[rs]),rs] + sum(mTEPES.pDuration[p,sc,n2]()*(OptModel.vHydroInflows[p,sc,n2,rs]*0.0036 - OptModel.vHydroOutflows[p,sc,n2,rs]*0.0036 - sum(OptModel.vTotalOutput[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (rs,h) in mTEPES.r2h) + sum(OptModel.vTotalOutput[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (h,rs) in mTEPES.h2r)
|
|
851
|
+
return (OptModel.vReservoirVolume[p,sc,mTEPES.n.prev(n,mTEPES.pReservoirTimeStep[rs]),rs] + sum(mTEPES.pDuration[p,sc,n2]()*(OptModel.vHydroInflows[p,sc,n2,rs]*0.0036 - OptModel.vHydroOutflows[p,sc,n2,rs]*0.0036 - sum(OptModel.vTotalOutput[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (rs,h) in mTEPES.r2h) + sum(OptModel.vTotalOutput[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (h,rs) in mTEPES.h2r) - sum(mTEPES.pEfficiency[h]*OptModel.vESSTotalCharge[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (rs,h) in mTEPES.r2p) + sum(mTEPES.pEfficiency[h]*OptModel.vESSTotalCharge[p,sc,n2,h]/mTEPES.pProductionFunctionHydro[h] for h in mTEPES.h if (h,rs) in mTEPES.p2r)) for n2 in list(mTEPES.n2)[mTEPES.n.ord(n)-mTEPES.pReservoirTimeStep[rs]:mTEPES.n.ord(n)]) == OptModel.vReservoirVolume[p,sc,n,rs] + OptModel.vReservoirSpillage[p,sc,n,rs] - sum(OptModel.vReservoirSpillage[p,sc,n,rsr] for rsr in mTEPES.rs if (rsr,rs) in mTEPES.r2r))
|
|
843
852
|
else:
|
|
844
853
|
return Constraint.Skip
|
|
845
854
|
else:
|
|
@@ -886,7 +895,7 @@ def GenerationOperationModelFormulationCommitment(OptModel, mTEPES, pIndLogConso
|
|
|
886
895
|
a2n[nr].append(ar)
|
|
887
896
|
|
|
888
897
|
def eMaxOutput2ndBlock(OptModel,n,nr):
|
|
889
|
-
if (p,nr) in mTEPES.pnr:
|
|
898
|
+
if (p,nr) in mTEPES.pnr and (nr not in mTEPES.es or (nr in mTEPES.es and (mTEPES.pTotalMaxCharge[nr] or mTEPES.pTotalEnergyInflows[nr]))):
|
|
890
899
|
if mTEPES.pMaxPower2ndBlock[p,sc,n,nr] and n != mTEPES.n.last():
|
|
891
900
|
return (OptModel.vOutput2ndBlock[p,sc,n,nr] + OptModel.vReserveUp [p,sc,n,nr]) / mTEPES.pMaxPower2ndBlock[p,sc,n,nr] <= OptModel.vCommitment[p,sc,n,nr] - OptModel.vStartUp[p,sc,n,nr] - OptModel.vShutDown[p,sc,mTEPES.n.next(n),nr]
|
|
892
901
|
elif mTEPES.pMaxPower2ndBlock[p,sc,n,nr] and n == mTEPES.n.last():
|
|
@@ -901,7 +910,7 @@ def GenerationOperationModelFormulationCommitment(OptModel, mTEPES, pIndLogConso
|
|
|
901
910
|
print('eMaxOutput2ndBlock ... ', len(getattr(OptModel, f'eMaxOutput2ndBlock_{p}_{sc}_{st}')), ' rows')
|
|
902
911
|
|
|
903
912
|
def eMinOutput2ndBlock(OptModel,n,nr):
|
|
904
|
-
if (p,nr) in mTEPES.pnr:
|
|
913
|
+
if (p,nr) in mTEPES.pnr and (nr not in mTEPES.es or (nr in mTEPES.es and (mTEPES.pTotalMaxCharge[nr] or mTEPES.pTotalEnergyInflows[nr]))):
|
|
905
914
|
if mTEPES.pMaxPower2ndBlock[p,sc,n,nr]:
|
|
906
915
|
return OptModel.vOutput2ndBlock[p,sc,n,nr] - OptModel.vReserveDown[p,sc,n,nr] >= 0.0
|
|
907
916
|
else:
|
|
@@ -914,7 +923,7 @@ def GenerationOperationModelFormulationCommitment(OptModel, mTEPES, pIndLogConso
|
|
|
914
923
|
print('eMinOutput2ndBlock ... ', len(getattr(OptModel, f'eMinOutput2ndBlock_{p}_{sc}_{st}')), ' rows')
|
|
915
924
|
|
|
916
925
|
def eTotalOutput(OptModel,n,nr):
|
|
917
|
-
if (p,nr) in mTEPES.pnr:
|
|
926
|
+
if (p,nr) in mTEPES.pnr and (nr not in mTEPES.es or (nr in mTEPES.es and (mTEPES.pTotalMaxCharge[nr] or mTEPES.pTotalEnergyInflows[nr]))):
|
|
918
927
|
if mTEPES.pMaxPowerElec[p,sc,n,nr]:
|
|
919
928
|
if mTEPES.pMinPowerElec[p,sc,n,nr] == 0.0:
|
|
920
929
|
return OptModel.vTotalOutput[p,sc,n,nr] == OptModel.vOutput2ndBlock[p,sc,n,nr] + mTEPES.pUpReserveActivation * OptModel.vReserveUp[p,sc,n,nr] - mTEPES.pDwReserveActivation * OptModel.vReserveDown[p,sc,n,nr]
|
|
@@ -961,7 +970,7 @@ def GenerationOperationModelFormulationCommitment(OptModel, mTEPES, pIndLogConso
|
|
|
961
970
|
def eMaxCommitment(OptModel,n,nr):
|
|
962
971
|
if len(mTEPES.g2g) and (p,nr) in mTEPES.pnr:
|
|
963
972
|
if sum(1 for g in mTEPES.nr if (nr,g) in mTEPES.g2g or (g,nr) in mTEPES.g2g):
|
|
964
|
-
return OptModel.vCommitment[p,sc,n,nr]
|
|
973
|
+
return OptModel.vCommitment[p,sc,n,nr] <= OptModel.vMaxCommitment[p,sc,nr]
|
|
965
974
|
else:
|
|
966
975
|
return Constraint.Skip
|
|
967
976
|
else:
|
|
@@ -1008,7 +1017,7 @@ def GenerationOperationModelFormulationRampMinTime(OptModel, mTEPES, pIndLogCons
|
|
|
1008
1017
|
StartTime = time.time()
|
|
1009
1018
|
|
|
1010
1019
|
def eRampUp(OptModel,n,nr):
|
|
1011
|
-
if (p,nr) in mTEPES.pnr:
|
|
1020
|
+
if (p,nr) in mTEPES.pnr and (nr not in mTEPES.es or (nr in mTEPES.es and (mTEPES.pTotalMaxCharge[nr] or mTEPES.pTotalEnergyInflows[nr]))):
|
|
1012
1021
|
if mTEPES.pRampUp[nr] and mTEPES.pIndBinGenRamps() == 1 and mTEPES.pRampUp[nr] < mTEPES.pMaxPower2ndBlock[p,sc,n,nr] and mTEPES.pDuration[p,sc,n]():
|
|
1013
1022
|
if n == mTEPES.n.first():
|
|
1014
1023
|
return (- max(mTEPES.pInitialOutput[p,sc,n,nr]() - mTEPES.pMinPowerElec[p,sc,n,nr],0.0) + OptModel.vOutput2ndBlock[p,sc,n,nr] + OptModel.vReserveUp [p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pRampUp[nr] <= OptModel.vCommitment[p,sc,n,nr] - OptModel.vStartUp[p,sc,n,nr]
|
|
@@ -1024,12 +1033,12 @@ def GenerationOperationModelFormulationRampMinTime(OptModel, mTEPES, pIndLogCons
|
|
|
1024
1033
|
print('eRampUp ... ', len(getattr(OptModel, f'eRampUp_{p}_{sc}_{st}')), ' rows')
|
|
1025
1034
|
|
|
1026
1035
|
def eRampDw(OptModel,n,nr):
|
|
1027
|
-
if (p,nr) in mTEPES.pnr:
|
|
1036
|
+
if (p,nr) in mTEPES.pnr and (nr not in mTEPES.es or (nr in mTEPES.es and (mTEPES.pTotalMaxCharge[nr] or mTEPES.pTotalEnergyInflows[nr]))):
|
|
1028
1037
|
if mTEPES.pRampDw[nr] and mTEPES.pIndBinGenRamps() == 1 and mTEPES.pRampDw[nr] < mTEPES.pMaxPower2ndBlock[p,sc,n,nr] and mTEPES.pDuration[p,sc,n]():
|
|
1029
1038
|
if n == mTEPES.n.first():
|
|
1030
1039
|
return (- max(mTEPES.pInitialOutput[p,sc,n,nr]() - mTEPES.pMinPowerElec[p,sc,n,nr],0.0) + OptModel.vOutput2ndBlock[p,sc,n,nr] - OptModel.vReserveDown[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pRampDw[nr] >= - mTEPES.pInitialUC[p,sc,n,nr]() + OptModel.vShutDown[p,sc,n,nr]
|
|
1031
1040
|
else:
|
|
1032
|
-
return (- OptModel.vOutput2ndBlock[p,sc,mTEPES.n.prev(n),nr]
|
|
1041
|
+
return (- OptModel.vOutput2ndBlock[p,sc,mTEPES.n.prev(n),nr] - OptModel.vReserveUp [p,sc,mTEPES.n.prev(n),nr] + OptModel.vOutput2ndBlock[p,sc,n,nr] + OptModel.vReserveDown[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pRampDw[nr] >= - OptModel.vCommitment[p,sc,mTEPES.n.prev(n),nr] + OptModel.vShutDown[p,sc,n,nr]
|
|
1033
1042
|
else:
|
|
1034
1043
|
return Constraint.Skip
|
|
1035
1044
|
else:
|
|
@@ -1084,25 +1093,25 @@ def GenerationOperationModelFormulationRampMinTime(OptModel, mTEPES, pIndLogCons
|
|
|
1084
1093
|
if pIndStableTimeDeadBand:
|
|
1085
1094
|
if mTEPES.pRampUp[nr]:
|
|
1086
1095
|
if n == mTEPES.n.first():
|
|
1087
|
-
return (- max(mTEPES.pInitialOutput[p,sc,n,nr]() - mTEPES.pMinPowerElec[p,sc,n,nr], 0.0) + OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pRampUp[nr]
|
|
1096
|
+
return (- max(mTEPES.pInitialOutput[p,sc,n,nr]() - mTEPES.pMinPowerElec[p,sc,n,nr], 0.0) + OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pRampUp[nr] <= OptModel.vRampUpState[p,sc,n,nr] - pEpsilon * (OptModel.vRampDwState[p,sc,n,nr] - OptModel.vStableState[p,sc,n,nr])
|
|
1088
1097
|
else:
|
|
1089
|
-
return (- OptModel.vOutput2ndBlock[p,sc,mTEPES.n.prev(n),nr] + OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pRampUp[nr]
|
|
1098
|
+
return (- OptModel.vOutput2ndBlock[p,sc,mTEPES.n.prev(n),nr] + OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pRampUp[nr] <= OptModel.vRampUpState[p,sc,n,nr] - pEpsilon * (OptModel.vRampDwState[p,sc,n,nr] - OptModel.vStableState[p,sc,n,nr])
|
|
1090
1099
|
else:
|
|
1091
1100
|
if n == mTEPES.n.first():
|
|
1092
|
-
return (- max(mTEPES.pInitialOutput[p,sc,n,nr]() - mTEPES.pMinPowerElec[p,sc,n,nr], 0.0) + OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pMaxPower2ndBlock[p,sc,n,nr]
|
|
1101
|
+
return (- max(mTEPES.pInitialOutput[p,sc,n,nr]() - mTEPES.pMinPowerElec[p,sc,n,nr], 0.0) + OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pMaxPower2ndBlock[p,sc,n,nr] <= OptModel.vRampUpState[p,sc,n,nr] - pEpsilon * (OptModel.vRampDwState[p,sc,n,nr] - OptModel.vStableState[p,sc,n,nr])
|
|
1093
1102
|
else:
|
|
1094
|
-
return (- OptModel.vOutput2ndBlock[p,sc,mTEPES.n.prev(n),nr] + OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pMaxPower2ndBlock[p,sc,n,nr]
|
|
1103
|
+
return (- OptModel.vOutput2ndBlock[p,sc,mTEPES.n.prev(n),nr] + OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pMaxPower2ndBlock[p,sc,n,nr] <= OptModel.vRampUpState[p,sc,n,nr] - pEpsilon * (OptModel.vRampDwState[p,sc,n,nr] - OptModel.vStableState[p,sc,n,nr])
|
|
1095
1104
|
else:
|
|
1096
1105
|
if mTEPES.pRampUp[nr]:
|
|
1097
1106
|
if n == mTEPES.n.first():
|
|
1098
|
-
return (- max(mTEPES.pInitialOutput[p,sc,n,nr]() - mTEPES.pMinPowerElec[p,sc,n,nr], 0.0) + OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pRampUp[nr]
|
|
1107
|
+
return (- max(mTEPES.pInitialOutput[p,sc,n,nr]() - mTEPES.pMinPowerElec[p,sc,n,nr], 0.0) + OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pRampUp[nr] <= OptModel.vRampUpState[p,sc,n,nr] - pEpsilon * OptModel.vRampDwState[p,sc,n,nr]
|
|
1099
1108
|
else:
|
|
1100
|
-
return (- OptModel.vOutput2ndBlock[p,sc,mTEPES.n.prev(n),nr] + OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pRampUp[nr]
|
|
1109
|
+
return (- OptModel.vOutput2ndBlock[p,sc,mTEPES.n.prev(n),nr] + OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pRampUp[nr] <= OptModel.vRampUpState[p,sc,n,nr] - pEpsilon * OptModel.vRampDwState[p,sc,n,nr]
|
|
1101
1110
|
else:
|
|
1102
1111
|
if n == mTEPES.n.first():
|
|
1103
|
-
return (- max(mTEPES.pInitialOutput[p,sc,n,nr]() - mTEPES.pMinPowerElec[p,sc,n,nr], 0.0) + OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pMaxPower2ndBlock[p,sc,n,nr]
|
|
1112
|
+
return (- max(mTEPES.pInitialOutput[p,sc,n,nr]() - mTEPES.pMinPowerElec[p,sc,n,nr], 0.0) + OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pMaxPower2ndBlock[p,sc,n,nr] <= OptModel.vRampUpState[p,sc,n,nr] - pEpsilon * OptModel.vRampDwState[p,sc,n,nr]
|
|
1104
1113
|
else:
|
|
1105
|
-
return (- OptModel.vOutput2ndBlock[p,sc,mTEPES.n.prev(n),nr] + OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pMaxPower2ndBlock[p,sc,n,nr]
|
|
1114
|
+
return (- OptModel.vOutput2ndBlock[p,sc,mTEPES.n.prev(n),nr] + OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pMaxPower2ndBlock[p,sc,n,nr] <= OptModel.vRampUpState[p,sc,n,nr] - pEpsilon * OptModel.vRampDwState[p,sc,n,nr]
|
|
1106
1115
|
else:
|
|
1107
1116
|
return Constraint.Skip
|
|
1108
1117
|
setattr(OptModel, f'eRampUpState_{p}_{sc}_{st}', Constraint(mTEPES.n, mTEPES.nr, rule=eRampUpState, doc='ramp up state [p.u.]'))
|
|
@@ -1115,25 +1124,25 @@ def GenerationOperationModelFormulationRampMinTime(OptModel, mTEPES, pIndLogCons
|
|
|
1115
1124
|
if pIndStableTimeDeadBand:
|
|
1116
1125
|
if mTEPES.pRampDw[nr]:
|
|
1117
1126
|
if n == mTEPES.n.first():
|
|
1118
|
-
return (max(mTEPES.pInitialOutput[p,sc,n,nr]() - mTEPES.pMinPowerElec[p,sc,n,nr], 0.0) - OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pRampDw[nr]
|
|
1127
|
+
return (max(mTEPES.pInitialOutput[p,sc,n,nr]() - mTEPES.pMinPowerElec[p,sc,n,nr], 0.0) - OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pRampDw[nr] <= OptModel.vRampDwState[p,sc,n,nr] - pEpsilon * (OptModel.vRampUpState[p,sc,n,nr] - OptModel.vStableState[p,sc,n,nr])
|
|
1119
1128
|
else:
|
|
1120
|
-
return (OptModel.vOutput2ndBlock[p,sc,mTEPES.n.prev(n),nr] - OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pRampDw[nr]
|
|
1129
|
+
return (OptModel.vOutput2ndBlock[p,sc,mTEPES.n.prev(n),nr] - OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pRampDw[nr] <= OptModel.vRampDwState[p,sc,n,nr] - pEpsilon * (OptModel.vRampUpState[p,sc,n,nr] - OptModel.vStableState[p,sc,n,nr])
|
|
1121
1130
|
else:
|
|
1122
1131
|
if n == mTEPES.n.first():
|
|
1123
|
-
return (max(mTEPES.pInitialOutput[p,sc,n,nr]() - mTEPES.pMinPowerElec[p,sc,n,nr], 0.0) - OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pMaxPower2ndBlock[p,sc,n,nr]
|
|
1132
|
+
return (max(mTEPES.pInitialOutput[p,sc,n,nr]() - mTEPES.pMinPowerElec[p,sc,n,nr], 0.0) - OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pMaxPower2ndBlock[p,sc,n,nr] <= OptModel.vRampDwState[p,sc,n,nr] - pEpsilon * (OptModel.vRampUpState[p,sc,n,nr] - OptModel.vStableState[p,sc,n,nr])
|
|
1124
1133
|
else:
|
|
1125
|
-
return (OptModel.vOutput2ndBlock[p,sc,mTEPES.n.prev(n),nr] - OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pMaxPower2ndBlock[p,sc,n,nr]
|
|
1134
|
+
return (OptModel.vOutput2ndBlock[p,sc,mTEPES.n.prev(n),nr] - OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pMaxPower2ndBlock[p,sc,n,nr] <= OptModel.vRampDwState[p,sc,n,nr] - pEpsilon * (OptModel.vRampUpState[p,sc,n,nr] - OptModel.vStableState[p,sc,n,nr])
|
|
1126
1135
|
else:
|
|
1127
1136
|
if mTEPES.pRampDw[nr]:
|
|
1128
1137
|
if n == mTEPES.n.first():
|
|
1129
|
-
return (max(mTEPES.pInitialOutput[p,sc,n,nr]() - mTEPES.pMinPowerElec[p,sc,n,nr], 0.0) - OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pRampDw[nr]
|
|
1138
|
+
return (max(mTEPES.pInitialOutput[p,sc,n,nr]() - mTEPES.pMinPowerElec[p,sc,n,nr], 0.0) - OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pRampDw[nr] <= OptModel.vRampDwState[p,sc,n,nr] - pEpsilon * OptModel.vRampUpState[p,sc,n,nr]
|
|
1130
1139
|
else:
|
|
1131
|
-
return (OptModel.vOutput2ndBlock[p,sc,mTEPES.n.prev(n),nr] - OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pRampDw[nr]
|
|
1140
|
+
return (OptModel.vOutput2ndBlock[p,sc,mTEPES.n.prev(n),nr] - OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pRampDw[nr] <= OptModel.vRampDwState[p,sc,n,nr] - pEpsilon * OptModel.vRampUpState[p,sc,n,nr]
|
|
1132
1141
|
else:
|
|
1133
1142
|
if n == mTEPES.n.first():
|
|
1134
|
-
return (max(mTEPES.pInitialOutput[p,sc,n,nr]() - mTEPES.pMinPowerElec[p,sc,n,nr], 0.0) - OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pMaxPower2ndBlock[p,sc,n,nr]
|
|
1143
|
+
return (max(mTEPES.pInitialOutput[p,sc,n,nr]() - mTEPES.pMinPowerElec[p,sc,n,nr], 0.0) - OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pMaxPower2ndBlock[p,sc,n,nr] <= OptModel.vRampDwState[p,sc,n,nr] - pEpsilon * OptModel.vRampUpState[p,sc,n,nr]
|
|
1135
1144
|
else:
|
|
1136
|
-
return (OptModel.vOutput2ndBlock[p,sc,mTEPES.n.prev(n),nr] - OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pMaxPower2ndBlock[p,sc,n,nr]
|
|
1145
|
+
return (OptModel.vOutput2ndBlock[p,sc,mTEPES.n.prev(n),nr] - OptModel.vOutput2ndBlock[p,sc,n,nr]) / mTEPES.pDuration[p,sc,n]() / mTEPES.pMaxPower2ndBlock[p,sc,n,nr] <= OptModel.vRampDwState[p,sc,n,nr] - pEpsilon * OptModel.vRampUpState[p,sc,n,nr]
|
|
1137
1146
|
else:
|
|
1138
1147
|
return Constraint.Skip
|
|
1139
1148
|
setattr(OptModel, f'eRampDwState_{p}_{sc}_{st}', Constraint(mTEPES.n, mTEPES.nr, rule=eRampDwState, doc='maximum ramp down [p.u.]'))
|
|
@@ -1144,7 +1153,7 @@ def GenerationOperationModelFormulationRampMinTime(OptModel, mTEPES, pIndLogCons
|
|
|
1144
1153
|
def eMinUpTime(OptModel,n,t):
|
|
1145
1154
|
if (p,t) in mTEPES.pg:
|
|
1146
1155
|
if mTEPES.pMustRun[t] == 0 and mTEPES.pIndBinGenMinTime() == 1 and (mTEPES.pMinPowerElec[p,sc,n,t] or mTEPES.pConstantVarCost[p,sc,n,t]) and t not in mTEPES.eh and mTEPES.pUpTime[t] > 1 and mTEPES.n.ord(n) >= mTEPES.pUpTime[t]:
|
|
1147
|
-
return sum(OptModel.vStartUp [p,sc,n2,t] for n2 in list(mTEPES.n2)[mTEPES.n.ord(n)-mTEPES.pUpTime[t]:mTEPES.n.ord(n)]) <= OptModel.vCommitment[p,sc,n,t]
|
|
1156
|
+
return sum(OptModel.vStartUp [p,sc,n2,t] for n2 in list(mTEPES.n2)[mTEPES.n.ord(n)+1-mTEPES.pUpTime[t]:mTEPES.n.ord(n)]) <= OptModel.vCommitment[p,sc,n,t]
|
|
1148
1157
|
else:
|
|
1149
1158
|
return Constraint.Skip
|
|
1150
1159
|
else:
|
|
@@ -1157,7 +1166,7 @@ def GenerationOperationModelFormulationRampMinTime(OptModel, mTEPES, pIndLogCons
|
|
|
1157
1166
|
def eMinDownTime(OptModel,n,t):
|
|
1158
1167
|
if (p,t) in mTEPES.pg:
|
|
1159
1168
|
if mTEPES.pMustRun[t] == 0 and mTEPES.pIndBinGenMinTime() == 1 and (mTEPES.pMinPowerElec[p,sc,n,t] or mTEPES.pConstantVarCost[p,sc,n,t]) and t not in mTEPES.eh and mTEPES.pDwTime[t] > 1 and mTEPES.n.ord(n) >= mTEPES.pDwTime[t]:
|
|
1160
|
-
return sum(OptModel.vShutDown[p,sc,n2,t] for n2 in list(mTEPES.n2)[mTEPES.n.ord(n)-mTEPES.pDwTime[t]:mTEPES.n.ord(n)]) <= 1 - OptModel.vCommitment[p,sc,n,t]
|
|
1169
|
+
return sum(OptModel.vShutDown[p,sc,n2,t] for n2 in list(mTEPES.n2)[mTEPES.n.ord(n)+1-mTEPES.pDwTime[t]:mTEPES.n.ord(n)]) <= 1 - OptModel.vCommitment[p,sc,n,t]
|
|
1161
1170
|
else:
|
|
1162
1171
|
return Constraint.Skip
|
|
1163
1172
|
else:
|
|
@@ -1286,7 +1295,7 @@ def NetworkOperationModelFormulation(OptModel, mTEPES, pIndLogConsole, p, sc, st
|
|
|
1286
1295
|
print('eNetCapacity2 ... ', len(getattr(OptModel, f'eNetCapacity2_{p}_{sc}_{st}')), ' rows')
|
|
1287
1296
|
|
|
1288
1297
|
def eKirchhoff2ndLaw1(OptModel,n,ni,nf,cc):
|
|
1289
|
-
if mTEPES.pIndBinSingleNode() == 0 and mTEPES.pElecNetPeriodIni[ni,nf,cc] <= p and mTEPES.pElecNetPeriodFin[ni,nf,cc] >= p and mTEPES.pLineX[ni,nf,cc]
|
|
1298
|
+
if mTEPES.pIndBinSingleNode() == 0 and mTEPES.pElecNetPeriodIni[ni,nf,cc] <= p and mTEPES.pElecNetPeriodFin[ni,nf,cc] >= p and mTEPES.pLineX[ni,nf,cc]:
|
|
1290
1299
|
if (ni,nf,cc) in mTEPES.lca:
|
|
1291
1300
|
return OptModel.vFlowElec[p,sc,n,ni,nf,cc] / mTEPES.pBigMFlowBck[ni,nf,cc]() - (OptModel.vTheta[p,sc,n,ni] - OptModel.vTheta[p,sc,n,nf]) / mTEPES.pLineX[ni,nf,cc] / mTEPES.pBigMFlowBck[ni,nf,cc]() * mTEPES.pSBase >= - 1 + OptModel.vLineCommit[p,sc,n,ni,nf,cc]
|
|
1292
1301
|
else:
|
|
@@ -1299,7 +1308,7 @@ def NetworkOperationModelFormulation(OptModel, mTEPES, pIndLogConsole, p, sc, st
|
|
|
1299
1308
|
print('eKirchhoff2ndLaw1 ... ', len(getattr(OptModel, f'eKirchhoff2ndLaw1_{p}_{sc}_{st}')), ' rows')
|
|
1300
1309
|
|
|
1301
1310
|
def eKirchhoff2ndLaw2(OptModel,n,ni,nf,cc):
|
|
1302
|
-
if mTEPES.pIndBinSingleNode() == 0 and mTEPES.pElecNetPeriodIni[ni,nf,cc] <= p and mTEPES.pElecNetPeriodFin[ni,nf,cc] >= p and mTEPES.pLineX[ni,nf,cc]
|
|
1311
|
+
if mTEPES.pIndBinSingleNode() == 0 and mTEPES.pElecNetPeriodIni[ni,nf,cc] <= p and mTEPES.pElecNetPeriodFin[ni,nf,cc] >= p and mTEPES.pLineX[ni,nf,cc]:
|
|
1303
1312
|
return OptModel.vFlowElec[p,sc,n,ni,nf,cc] / mTEPES.pBigMFlowFrw[ni,nf,cc]() - (OptModel.vTheta[p,sc,n,ni] - OptModel.vTheta[p,sc,n,nf]) / mTEPES.pLineX[ni,nf,cc] / mTEPES.pBigMFlowFrw[ni,nf,cc]() * mTEPES.pSBase <= 1 - OptModel.vLineCommit[p,sc,n,ni,nf,cc]
|
|
1304
1313
|
else:
|
|
1305
1314
|
return Constraint.Skip
|