Skip to content

Commit

Permalink
added colum of MEUR/year in cost summary files and information regard…
Browse files Browse the repository at this point in the history
…ing detected infeasibilities
  • Loading branch information
arght committed Oct 16, 2024
1 parent 026545f commit e665e61
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 43 deletions.
10 changes: 6 additions & 4 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
Change Log
=============

[4.17.8] - 2024-10-04
[4.17.8] - 2024-10-16
-----------------------
[FIXED] lower bound only for VRE units
[FIXED] computation of curtailment in the output results for generation candidates
- [CHANGED] added colum of MEUR/year in cost summary files
- [CHANGED] added information regarding detected infeasibilities
- [FIXED] lower bound only for VRE units
- [FIXED] computation of curtailment in the output results for generation candidates

[4.17.7] - 2024-09-20
-----------------------
[CHANGED] redefinition of all sets, removing the order of the elements, and the lambda function to filter the elements
- [CHANGED] redefinition of all sets, removing the order of the elements, and the lambda function to filter the elements
-[CHANGED] enabling assert of the objective function in the test run

[4.17.5] - 2024-09-18
Expand Down
6 changes: 3 additions & 3 deletions openTEPES/openTEPES.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - October 04, 2024
Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - October 16, 2024
"""

# import dill as pickle
Expand Down Expand Up @@ -39,8 +39,8 @@ def openTEPES_run(DirName, CaseName, SolverName, pIndOutputResults, pIndLogConso
idxDict['y' ] = 1

#%% model declaration
mTEPES = ConcreteModel('Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - Version 4.17.8 - October 04, 2024')
print( 'Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - Version 4.17.8 - October 04, 2024', file=open(_path+'/openTEPES_version_'+CaseName+'.log','w'))
mTEPES = ConcreteModel('Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - Version 4.17.8 - October 16, 2024')
print( 'Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - Version 4.17.8 - October 16, 2024', file=open(_path+'/openTEPES_version_'+CaseName+'.log','w'))

pIndOutputResults = [j for i,j in idxDict.items() if i == pIndOutputResults][0]
pIndLogConsole = [j for i,j in idxDict.items() if i == pIndLogConsole ][0]
Expand Down
24 changes: 12 additions & 12 deletions openTEPES/openTEPES_InputData.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - October 04, 2024
Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - October 16, 2024
"""

import datetime
Expand Down Expand Up @@ -1740,11 +1740,11 @@ def setVariableBounds(mTEPES, OptModel) -> None:
[OptModel.vIniInventory [p,sc,n,ec].setlb(mTEPES.pMinStorage [p,sc,n,ec] ) for p,sc,n,ec in mTEPES.psnec]
[OptModel.vIniInventory [p,sc,n,ec].setub(mTEPES.pMaxStorage [p,sc,n,ec] ) for p,sc,n,ec in mTEPES.psnec]

[OptModel.vESSTotalCharge[p,sc,n,eh].setub(mTEPES.pMaxCharge [p,sc,n,eh]) for p,sc,n,eh in mTEPES.psneh]
[OptModel.vCharge2ndBlock[p,sc,n,eh].setub(mTEPES.pMaxCharge2ndBlock[p,sc,n,eh]) for p,sc,n,eh in mTEPES.psneh]
[OptModel.vESSReserveUp [p,sc,n,eh].setub(mTEPES.pMaxCharge2ndBlock[p,sc,n,eh]) for p,sc,n,eh in mTEPES.psneh]
[OptModel.vESSReserveDown[p,sc,n,eh].setub(mTEPES.pMaxCharge2ndBlock[p,sc,n,eh]) for p,sc,n,eh in mTEPES.psneh]
[OptModel.vENS [p,sc,n,nd].setub(mTEPES.pDemandElecAbs [p,sc,n,nd]) for p,sc,n,nd in mTEPES.psnnd]
[OptModel.vESSTotalCharge[p,sc,n,eh].setub(mTEPES.pMaxCharge [p,sc,n,eh] ) for p,sc,n,eh in mTEPES.psneh]
[OptModel.vCharge2ndBlock[p,sc,n,eh].setub(mTEPES.pMaxCharge2ndBlock[p,sc,n,eh] ) for p,sc,n,eh in mTEPES.psneh]
[OptModel.vESSReserveUp [p,sc,n,eh].setub(mTEPES.pMaxCharge2ndBlock[p,sc,n,eh] ) for p,sc,n,eh in mTEPES.psneh]
[OptModel.vESSReserveDown[p,sc,n,eh].setub(mTEPES.pMaxCharge2ndBlock[p,sc,n,eh] ) for p,sc,n,eh in mTEPES.psneh]
[OptModel.vENS [p,sc,n,nd].setub(mTEPES.pDemandElecAbs [p,sc,n,nd] ) for p,sc,n,nd in mTEPES.psnnd]

if mTEPES.pIndHydroTopology == 1:
[OptModel.vHydroInflows [p,sc,n,rc].setub(mTEPES.pHydroInflows[p,sc,n,rc]()) for p,sc,n,rc in mTEPES.psnrc]
Expand Down Expand Up @@ -2406,32 +2406,32 @@ def DetectInfeasibilities(mTEPES) -> None:
for es in mTEPES.es:
# detecting infeasibility: total min ESS output greater than total inflows, total max ESS charge lower than total outflows
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:
raise ValueError('### Total minimum output greater than total inflows for ESS unit ', es)
raise ValueError('### Total minimum output greater than total inflows for ESS unit ', es, 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))
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:
raise ValueError('### Total maximum charge lower than total outflows for ESS unit ', es)
raise ValueError('### Total maximum charge lower than total outflows for ESS unit ', es, 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))

# detect inventory infeasibility
for p,sc,n,es in mTEPES.ps*mTEPES.nesc:
if (p,es) in mTEPES.pes:
if mTEPES.pMaxCapacity[p,sc,n,es]:
if mTEPES.n.ord(n) == mTEPES.pStorageTimeStep[es]:
if mTEPES.pIniInventory[p,sc,n,es]() + sum(mTEPES.pDuration[p,sc,n2]()*(mTEPES.pEnergyInflows[p,sc,n2,es]() - mTEPES.pMinPowerElec[p,sc,n2,es] + mTEPES.pEfficiency[es]*mTEPES.pMaxCharge[p,sc,n2,es]) for n2 in list(mTEPES.n2)[mTEPES.n.ord(n)-mTEPES.pStorageTimeStep[es]:mTEPES.n.ord(n)]) < mTEPES.pMinStorage[p,sc,n,es]:
raise ValueError('### Inventory equation violation ', p, sc, n, es)
raise ValueError('### Inventory equation violation ', p, sc, n, es, mTEPES.pIniInventory[p,sc,n,es]() + sum(mTEPES.pDuration[p,sc,n2]()*(mTEPES.pEnergyInflows[p,sc,n2,es]() - mTEPES.pMinPowerElec[p,sc,n2,es] + mTEPES.pEfficiency[es]*mTEPES.pMaxCharge[p,sc,n2,es]) for n2 in list(mTEPES.n2)[mTEPES.n.ord(n)-mTEPES.pStorageTimeStep[es]:mTEPES.n.ord(n)]), mTEPES.pMinStorage[p,sc,n,es])
elif mTEPES.n.ord(n) > mTEPES.pStorageTimeStep[es]:
if mTEPES.pMaxStorage[p,sc,mTEPES.n.prev(n,mTEPES.pStorageTimeStep[es]),es] + sum(mTEPES.pDuration[p,sc,n2]()*(mTEPES.pEnergyInflows[p,sc,n2,es]() - mTEPES.pMinPowerElec[p,sc,n2,es] + mTEPES.pEfficiency[es]*mTEPES.pMaxCharge[p,sc,n2,es]) for n2 in list(mTEPES.n2)[mTEPES.n.ord(n)-mTEPES.pStorageTimeStep[es]:mTEPES.n.ord(n)]) < mTEPES.pMinStorage[p,sc,n,es]:
raise ValueError('### Inventory equation violation ', p, sc, n, es)
raise ValueError('### Inventory equation violation ', p, sc, n, es, mTEPES.pMaxStorage[p,sc,mTEPES.n.prev(n,mTEPES.pStorageTimeStep[es]),es] + sum(mTEPES.pDuration[p,sc,n2]()*(mTEPES.pEnergyInflows[p,sc,n2,es]() - mTEPES.pMinPowerElec[p,sc,n2,es] + mTEPES.pEfficiency[es]*mTEPES.pMaxCharge[p,sc,n2,es]) for n2 in list(mTEPES.n2)[mTEPES.n.ord(n)-mTEPES.pStorageTimeStep[es]:mTEPES.n.ord(n)]), mTEPES.pMinStorage[p,sc,n,es])

# detect minimum energy infeasibility
for p,sc,n,g in mTEPES.ps*mTEPES.ngen:
if (p,g) in mTEPES.pg:
if (p,sc,g) in mTEPES.gm:
if sum((mTEPES.pMaxPowerElec[p,sc,n2,g] - mTEPES.pMinEnergy[p,sc,n2,g])*mTEPES.pDuration[p,sc,n2]() for n2 in list(mTEPES.n2)[mTEPES.n.ord(n) - mTEPES.pEnergyTimeStep[g]:mTEPES.n.ord(n)]) < 0.0:
raise ValueError('### Minimum energy violation ', p, sc, n, g)
raise ValueError('### Minimum energy violation ', p, sc, n, g, sum((mTEPES.pMaxPowerElec[p,sc,n2,g] - mTEPES.pMinEnergy[p,sc,n2,g])*mTEPES.pDuration[p,sc,n2]() for n2 in list(mTEPES.n2)[mTEPES.n.ord(n) - mTEPES.pEnergyTimeStep[g]:mTEPES.n.ord(n)]))

# detecting reserve margin infeasibility
for p,ar in mTEPES.p*mTEPES.ar:
if sum(mTEPES.pRatedMaxPowerElec[g] * mTEPES.pAvailability[g]() / (1.0-mTEPES.pEFOR[g]) for g in mTEPES.g if (p,g) in mTEPES.pg and (ar,g) in mTEPES.a2g) < mTEPES.pDemandElecPeak[p,ar] * mTEPES.pReserveMargin[p,ar]:
raise ValueError('### Reserve margin infeasibility ', p, ar)
raise ValueError('### Reserve margin infeasibility ', p, ar, sum(mTEPES.pRatedMaxPowerElec[g] * mTEPES.pAvailability[g]() / (1.0-mTEPES.pEFOR[g]) for g in mTEPES.g if (p,g) in mTEPES.pg and (ar,g) in mTEPES.a2g), mTEPES.pDemandElecPeak[p,ar] * mTEPES.pReserveMargin[p,ar])

DetectInfeasibilities(mTEPES)

Expand Down
4 changes: 2 additions & 2 deletions openTEPES/openTEPES_Main.py
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@
# For more information on this, and how to apply and follow the GNU AGPL, see
# <https://www.gnu.org/licenses/>.

# Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - October 04, 2024
# Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - October 16, 2024
# simplicity and transparency in power systems planning

# Developed by
Expand All @@ -685,7 +685,7 @@
# import pkg_resources
from .openTEPES import openTEPES_run

print('\033[1;32mOpen Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - Version 4.17.8 - October 04, 2024\033[0m')
print('\033[1;32mOpen Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - Version 4.17.8 - October 16, 2024\033[0m')
print('\033[34m#### Academic research license - for non-commercial use only ####\033[0m \n')

parser = argparse.ArgumentParser(description='Introducing main parameters...')
Expand Down
Loading

0 comments on commit e665e61

Please sign in to comment.