From e665e614afec218ecb431b3b1183ac6c77706178 Mon Sep 17 00:00:00 2001 From: Andres Ramos <61053256+arght@users.noreply.github.com> Date: Wed, 16 Oct 2024 11:25:45 +0200 Subject: [PATCH] added colum of MEUR/year in cost summary files and information regarding detected infeasibilities --- CHANGELOG.rst | 10 +++--- openTEPES/openTEPES.py | 6 ++-- openTEPES/openTEPES_InputData.py | 24 ++++++------- openTEPES/openTEPES_Main.py | 4 +-- openTEPES/openTEPES_OutputResults.py | 54 ++++++++++++++++------------ 5 files changed, 55 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2527865b..daacd9b4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -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 diff --git a/openTEPES/openTEPES.py b/openTEPES/openTEPES.py index 3831fd7d..76169567 100644 --- a/openTEPES/openTEPES.py +++ b/openTEPES/openTEPES.py @@ -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 @@ -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] diff --git a/openTEPES/openTEPES_InputData.py b/openTEPES/openTEPES_InputData.py index c1e1377a..3030f1c9 100644 --- a/openTEPES/openTEPES_InputData.py +++ b/openTEPES/openTEPES_InputData.py @@ -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 @@ -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] @@ -2406,9 +2406,9 @@ 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: @@ -2416,22 +2416,22 @@ def DetectInfeasibilities(mTEPES) -> None: 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) diff --git a/openTEPES/openTEPES_Main.py b/openTEPES/openTEPES_Main.py index 7568ed1d..fd9e5d60 100644 --- a/openTEPES/openTEPES_Main.py +++ b/openTEPES/openTEPES_Main.py @@ -660,7 +660,7 @@ # For more information on this, and how to apply and follow the GNU AGPL, see # . -# 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 @@ -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...') diff --git a/openTEPES/openTEPES_OutputResults.py b/openTEPES/openTEPES_OutputResults.py index a7311285..79c5b277 100644 --- a/openTEPES/openTEPES_OutputResults.py +++ b/openTEPES/openTEPES_OutputResults.py @@ -1,5 +1,5 @@ """ -Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - October 03, 2024 +Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - October 16, 2024 """ import time @@ -1790,20 +1790,25 @@ def CostSummaryResults(DirName, CaseName, OptModel, mTEPES): _path = os.path.join(DirName, CaseName) StartTime = time.time() - SysCost = pd.Series(data=[ OptModel.vTotalSCost() ], index=[''] ).to_frame(name='Total System Cost').stack() - GenInvCost = pd.Series(data=[mTEPES.pDiscountedWeight[p] * sum(mTEPES.pGenInvestCost[gc ] * OptModel.vGenerationInvest[p,gc ]() for gc in mTEPES.gc if (p,gc) in mTEPES.pgc) for p in mTEPES.p], index=mTEPES.p).to_frame(name='Generation Investment Cost').stack() - GenRetCost = pd.Series(data=[mTEPES.pDiscountedWeight[p] * sum(mTEPES.pGenRetireCost[gd ] * OptModel.vGenerationRetire[p,gd ]() for gd in mTEPES.gd if (p,gd) in mTEPES.pgd) for p in mTEPES.p], index=mTEPES.p).to_frame(name='Generation Retirement Cost').stack() + # SysCost = pd.Series(data=[ OptModel.vTotalSCost() ], index=[''] ).to_frame(name='Total System Cost').stack() + GenInvCost = pd.Series(data=[mTEPES.pDiscountedWeight[p] * sum(mTEPES.pGenInvestCost[gc ] * OptModel.vGenerationInvest[p,gc ]() for gc in mTEPES.gc if (p,gc) in mTEPES.pgc) for p in mTEPES.p], index=mTEPES.p).to_frame(name='Generation Investment Cost').stack() + GenRetCost = pd.Series(data=[mTEPES.pDiscountedWeight[p] * sum(mTEPES.pGenRetireCost[gd ] * OptModel.vGenerationRetire[p,gd ]() for gd in mTEPES.gd if (p,gd) in mTEPES.pgd) for p in mTEPES.p], index=mTEPES.p).to_frame(name='Generation Retirement Cost').stack() if mTEPES.pIndHydroTopology == 1: - RsrInvCost = pd.Series(data=[mTEPES.pDiscountedWeight[p] * sum(mTEPES.pRsrInvestCost[rc ] * OptModel.vReservoirInvest [p,rc ]() for rc in mTEPES.rn if (p,rc) in mTEPES.prc) for p in mTEPES.p], index=mTEPES.p).to_frame(name='Reservoir Investment Cost').stack() + RsrInvCost = pd.Series(data=[mTEPES.pDiscountedWeight[p] * sum(mTEPES.pRsrInvestCost[rc ] * OptModel.vReservoirInvest [p,rc ]() for rc in mTEPES.rn if (p,rc) in mTEPES.prc) for p in mTEPES.p], index=mTEPES.p).to_frame(name='Reservoir Investment Cost' ).stack() else: - RsrInvCost = pd.Series(data=[0.0 for p in mTEPES.p], index=mTEPES.p).to_frame(name='Reservoir Investment Cost').stack() - NetInvCost = pd.Series(data=[mTEPES.pDiscountedWeight[p] * sum(mTEPES.pNetFixedCost [lc ] * OptModel.vNetworkInvest [p,lc ]() for lc in mTEPES.lc if (p,lc) in mTEPES.plc) for p in mTEPES.p], index=mTEPES.p).to_frame(name='Network Investment Cost').stack() - GenCost = pd.Series(data=[mTEPES.pDiscountedWeight[p] * sum(mTEPES.pScenProb [p,sc]() * OptModel.vTotalGCost [p,sc,n]() for sc,n in mTEPES.sc*mTEPES.n if (p,sc) in mTEPES.ps ) for p in mTEPES.p], index=mTEPES.p).to_frame(name='Generation Operation Cost').stack() - ConCost = pd.Series(data=[mTEPES.pDiscountedWeight[p] * sum(mTEPES.pScenProb [p,sc]() * OptModel.vTotalCCost [p,sc,n]() for sc,n in mTEPES.sc*mTEPES.n if (p,sc) in mTEPES.ps ) for p in mTEPES.p], index=mTEPES.p).to_frame(name='Consumption Operation Cost').stack() - EmiCost = pd.Series(data=[mTEPES.pDiscountedWeight[p] * sum(mTEPES.pScenProb [p,sc]() * OptModel.vTotalECost [p,sc,n]() for sc,n in mTEPES.sc*mTEPES.n if (p,sc) in mTEPES.ps ) for p in mTEPES.p], index=mTEPES.p).to_frame(name='Emission Cost').stack() - RelCost = pd.Series(data=[mTEPES.pDiscountedWeight[p] * sum(mTEPES.pScenProb [p,sc]() * OptModel.vTotalRCost [p,sc,n]() for sc,n in mTEPES.sc*mTEPES.n if (p,sc) in mTEPES.ps ) for p in mTEPES.p], index=mTEPES.p).to_frame(name='Reliability Cost').stack() + RsrInvCost = pd.Series(data=[0.0 for p in mTEPES.p], index=mTEPES.p).to_frame(name='Reservoir Investment Cost' ).stack() + NetInvCost = pd.Series(data=[mTEPES.pDiscountedWeight[p] * sum(mTEPES.pNetFixedCost [lc ] * OptModel.vNetworkInvest [p,lc ]() for lc in mTEPES.lc if (p,lc) in mTEPES.plc) for p in mTEPES.p], index=mTEPES.p).to_frame(name='Network Investment Cost' ).stack() + GenCost = pd.Series(data=[mTEPES.pDiscountedWeight[p] * sum(mTEPES.pScenProb [p,sc]() * OptModel.vTotalGCost [p,sc,n]() for sc,n in mTEPES.sc*mTEPES.n if (p,sc) in mTEPES.ps ) for p in mTEPES.p], index=mTEPES.p).to_frame(name='Generation Operation Cost' ).stack() + ConCost = pd.Series(data=[mTEPES.pDiscountedWeight[p] * sum(mTEPES.pScenProb [p,sc]() * OptModel.vTotalCCost [p,sc,n]() for sc,n in mTEPES.sc*mTEPES.n if (p,sc) in mTEPES.ps ) for p in mTEPES.p], index=mTEPES.p).to_frame(name='Consumption Operation Cost').stack() + EmiCost = pd.Series(data=[mTEPES.pDiscountedWeight[p] * sum(mTEPES.pScenProb [p,sc]() * OptModel.vTotalECost [p,sc,n]() for sc,n in mTEPES.sc*mTEPES.n if (p,sc) in mTEPES.ps ) for p in mTEPES.p], index=mTEPES.p).to_frame(name='Emission Cost' ).stack() + RelCost = pd.Series(data=[mTEPES.pDiscountedWeight[p] * sum(mTEPES.pScenProb [p,sc]() * OptModel.vTotalRCost [p,sc,n]() for sc,n in mTEPES.sc*mTEPES.n if (p,sc) in mTEPES.ps ) for p in mTEPES.p], index=mTEPES.p).to_frame(name='Reliability Cost' ).stack() + CostSummary = pd.concat([GenInvCost, GenRetCost, RsrInvCost, NetInvCost, GenCost, ConCost, EmiCost, RelCost]).reset_index().rename(columns={'level_0': 'Period', 'level_1': 'Cost', 0: 'MEUR'}) + CostSummary['MEUR/year'] = CostSummary['MEUR'] + for p in mTEPES.p: + CostSummary.loc[CostSummary['Period'] == p, 'MEUR/year'] = CostSummary.loc[CostSummary['Period'] == p, 'MEUR'] / mTEPES.pDiscountedWeight[p] + CostSummary.to_csv(_path+'/oT_Result_CostSummary_'+CaseName+'.csv', sep=',', index=False) + # DemPayment = pd.Series(data=[mTEPES.pDiscountedWeight[p] * sum(mTEPES.pScenProb [p,sc]() * mTEPES.pLoadLevelDuration[p,sc,n]() * mTEPES.pDemandElec[p,sc,n,nd] * OptModel.LSRMC [p,sc,n,nd] for sc,n,nd in mTEPES.sc*mTEPES.n*mTEPES.nd if (p,sc) in mTEPES.ps )/1e3 for p in mTEPES.p], index=mTEPES.p).to_frame(name='Demand Payment' ).stack() - CostSummary = pd.concat([SysCost, GenInvCost, GenRetCost, RsrInvCost, NetInvCost, GenCost, ConCost, EmiCost, RelCost]).reset_index().rename(columns={'level_0': 'Period', 'level_1': 'Costs', 0: 'MEUR'}).to_csv(_path+'/oT_Result_CostSummary_'+CaseName+'.csv', sep=',', index=False) WritingResultsTime = time.time() - StartTime print('Writing cost summary results ... ', round(WritingResultsTime), 's') @@ -1938,12 +1943,13 @@ def EconomicResults(DirName, CaseName, OptModel, mTEPES, pIndAreaOutput, pIndPlo OutputToFile = pd.Series(data=[mTEPES.pDiscountedWeight[p] * mTEPES.pScenProb[p,sc]() * mTEPES.pLoadLevelDuration[p,sc,n]() * mTEPES.pLinearOMCost [re] * OptModel.vTotalOutput [p,sc,n,re]() for p,sc,n,re in mTEPES.psnre if (p,re) in mTEPES.pre], index=pd.Index(mTEPES.psnre)) OutputToFile.to_frame(name='MEUR').reset_index().pivot_table(index=['level_0','level_1','level_2'], columns='level_3', values='MEUR', aggfunc='sum').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).to_csv(_path+'/oT_Result_GenerationCostOandM_' +CaseName+'.csv', sep=',') - if len(mTEPES.es) and sum(mTEPES.pIndOperReserve[es] for es in mTEPES.es if mTEPES.pIndOperReserve[es] == 0): + if len(mTEPES.es): OutputToFile = pd.Series(data=[ mTEPES.pDiscountedWeight[p] * mTEPES.pScenProb[p,sc]() * mTEPES.pLoadLevelDuration[p,sc,n]() * mTEPES.pLinearVarCost[p,sc,n,eh] * OptModel.vESSTotalCharge[p,sc,n,eh]() for p,sc,n,eh in mTEPES.psneh if (p,eh) in mTEPES.peh], index=pd.Index(mTEPES.psneh)) OutputToFile.to_frame(name='MEUR').reset_index().pivot_table(index=['level_0','level_1','level_2'], columns='level_3', values='MEUR', aggfunc='sum').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).to_csv(_path+'/oT_Result_ConsumptionCostOperation_' +CaseName+'.csv', sep=',') - OutputToFile = pd.Series(data=[(mTEPES.pDiscountedWeight[p] * mTEPES.pScenProb[p,sc]() * mTEPES.pLoadLevelWeight[p,sc,n]() * mTEPES.pOperReserveCost[eh] * OptModel.vESSReserveUp [p,sc,n,eh]() + - mTEPES.pDiscountedWeight[p] * mTEPES.pScenProb[p,sc]() * mTEPES.pLoadLevelWeight[p,sc,n]() * mTEPES.pOperReserveCost[eh] * OptModel.vESSReserveDown[p,sc,n,eh]()) for p,sc,n,eh in mTEPES.psneh if (p,eh) in mTEPES.peh], index=pd.Index(mTEPES.psneh)) - OutputToFile.to_frame(name='MEUR').reset_index().pivot_table(index=['level_0','level_1','level_2'], columns='level_3', values='MEUR', aggfunc='sum').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).to_csv(_path+'/oT_Result_ConsumptionCostOperatingReserve_'+CaseName+'.csv', sep=',') + if sum(mTEPES.pIndOperReserve[es] for es in mTEPES.es if mTEPES.pIndOperReserve[es] == 0): + OutputToFile = pd.Series(data=[(mTEPES.pDiscountedWeight[p] * mTEPES.pScenProb[p,sc]() * mTEPES.pLoadLevelWeight[p,sc,n]() * mTEPES.pOperReserveCost[eh] * OptModel.vESSReserveUp [p,sc,n,eh]() + + mTEPES.pDiscountedWeight[p] * mTEPES.pScenProb[p,sc]() * mTEPES.pLoadLevelWeight[p,sc,n]() * mTEPES.pOperReserveCost[eh] * OptModel.vESSReserveDown[p,sc,n,eh]()) for p,sc,n,eh in mTEPES.psneh if (p,eh) in mTEPES.peh], index=pd.Index(mTEPES.psneh)) + OutputToFile.to_frame(name='MEUR').reset_index().pivot_table(index=['level_0','level_1','level_2'], columns='level_3', values='MEUR', aggfunc='sum').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).to_csv(_path+'/oT_Result_ConsumptionCostOperatingReserve_'+CaseName+'.csv', sep=',') OutputToFile = pd.Series(data=[mTEPES.pDiscountedWeight[p] * mTEPES.pScenProb[p,sc]() * mTEPES.pLoadLevelDuration[p,sc,n]() * mTEPES.pEmissionVarCost[p,sc,n,g] * OptModel.vTotalOutput[p,sc,n,g]() for p,sc,n,g in mTEPES.psng if (p,g) in mTEPES.pg], index=pd.Index(mTEPES.psng)) OutputToFile.to_frame(name='MEUR').reset_index().pivot_table(index=['level_0','level_1','level_2'], columns='level_3', values='MEUR', aggfunc='sum').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).to_csv(_path+'/oT_Result_GenerationCostEmission_' +CaseName+'.csv', sep=',') @@ -1991,22 +1997,26 @@ def Transformation1(df, _name): OutputResults3 = pd.Series(data=[mTEPES.pDiscountedWeight[p] * mTEPES.pScenProb[p,sc]() * mTEPES.pLoadLevelDuration[p,sc,n]() * mTEPES.pLinearOMCost [re] * OptModel.vTotalOutput [p,sc,n,re]() for p,sc,n,re in sPSNRE if (p,re) in mTEPES.pre], index=pd.Index(sPSNRE)) OutputResults3 = Transformation1(OutputResults3, 'Generation O&M Cost') - if len(mTEPES.eh) and sum(mTEPES.pIndOperReserve[eh] for eh in mTEPES.eh if mTEPES.pIndOperReserve[eh] == 0): + if len(mTEPES.eh): sPSNES = [(p,sc,n,eh) for p,sc,n,eh in mTEPES.psneh if eh in g2a[ar]] if len(sPSNES): OutputResults4 = pd.Series(data=[ mTEPES.pDiscountedWeight[p] * mTEPES.pScenProb[p,sc]() * mTEPES.pLoadLevelDuration[p,sc,n]() * mTEPES.pLinearVarCost [p,sc,n,eh] * OptModel.vESSTotalCharge[p,sc,n,eh]() for p,sc,n,eh in sPSNES if (p,eh) in mTEPES.peh], index=pd.Index(sPSNES)) - OutputResults5 = pd.Series(data=[(mTEPES.pDiscountedWeight[p] * mTEPES.pScenProb[p,sc]() * mTEPES.pLoadLevelWeight [p,sc,n]() * mTEPES.pOperReserveCost[ eh] * OptModel.vESSReserveUp [p,sc,n,eh]() + - mTEPES.pDiscountedWeight[p] * mTEPES.pScenProb[p,sc]() * mTEPES.pLoadLevelWeight [p,sc,n]() * mTEPES.pOperReserveCost[ eh] * OptModel.vESSReserveDown[p,sc,n,eh]()) for p,sc,n,eh in sPSNES if (p,eh) in mTEPES.peh], index=pd.Index(sPSNES)) OutputResults4 = Transformation1(OutputResults4, 'Consumption Operation Cost') - OutputResults5 = Transformation1(OutputResults5, 'Consumption Operating Reserve Cost') + if sum(mTEPES.pIndOperReserve[eh] for eh in mTEPES.eh if mTEPES.pIndOperReserve[eh] == 0): + OutputResults5 = pd.Series(data=[(mTEPES.pDiscountedWeight[p] * mTEPES.pScenProb[p,sc]() * mTEPES.pLoadLevelWeight [p,sc,n]() * mTEPES.pOperReserveCost[ eh] * OptModel.vESSReserveUp [p,sc,n,eh]() + + mTEPES.pDiscountedWeight[p] * mTEPES.pScenProb[p,sc]() * mTEPES.pLoadLevelWeight [p,sc,n]() * mTEPES.pOperReserveCost[ eh] * OptModel.vESSReserveDown[p,sc,n,eh]()) for p,sc,n,eh in sPSNES if (p,eh) in mTEPES.peh], index=pd.Index(sPSNES)) + OutputResults5 = Transformation1(OutputResults5, 'Consumption Operating Reserve Cost') sPSNND = [(p,sc,n,nd) for p,sc,n,nd in mTEPES.psnnd if (nd,ar) in mTEPES.ndar] if len(sPSNND): OutputResults7 = pd.Series(data=[mTEPES.pDiscountedWeight[p] * mTEPES.pScenProb[p,sc]() * mTEPES.pLoadLevelDuration[p,sc,n]() * mTEPES.pENSCost() * OptModel.vENS [p,sc,n,nd]() for p,sc,n,nd in sPSNND], index=pd.Index(sPSNND)) OutputResults7 = Transformation1(OutputResults7, 'Reliability Cost') - OutputResults = pd.concat([OutputResults1, OutputResults2, OutputResults3, OutputResults4, OutputResults5, OutputResults6, OutputResults7], axis=0) - OutputResults.rename_axis(['Period', 'Scenario', 'Cost'], axis=0).to_csv(_path+'/oT_Result_CostSummary_'+ar+'_'+CaseName+'.csv', sep=',') + OutputResults = pd.concat([OutputResults1, OutputResults2, OutputResults3, OutputResults4, OutputResults5, OutputResults6, OutputResults7]).reset_index().rename(columns={'level_0': 'Period', 'level_1': 'Scenario', 'level_2': 'Cost', 0: 'MEUR'}) + OutputResults['MEUR/year'] = OutputResults['MEUR'] + for p,sc in mTEPES.psc: + OutputResults.loc[(OutputResults['Period'] == p) & (OutputResults['Scenario'] == sc), 'MEUR/year'] = OutputResults.loc[(OutputResults['Period'] == p) & (OutputResults['Scenario'] == sc), 'MEUR'] / mTEPES.pDiscountedWeight[p] / mTEPES.pScenProb[p,sc]() + OutputResults.to_csv(_path+'/oT_Result_CostSummary_'+ar+'_'+CaseName+'.csv', sep=',', index=False) sPSSTNNDG = [(p,sc,st,n,nd,g) for p,sc,st,n,nd,g in mTEPES.s2n*mTEPES.n2g if (p,g) in mTEPES.pg and (p,sc,n) in mTEPES.psn] OutputResults = pd.Series(data=[mTEPES.pDuals["".join(["eBalanceElec_", str(p), "_", str(sc), "_", str(st), "('", str(n), "', '", str(nd), "')"])]/mTEPES.pPeriodProb[p,sc]()/mTEPES.pLoadLevelDuration[p,sc,n]()*OptModel.vTotalOutput [p,sc,n,g]()*np.sign(getattr(OptModel, 'eBalanceElec_'+str(p)+'_'+str(sc)+'_'+str(st))[n,nd].ub+1e-10) for p,sc,st,n,nd,g in sPSSTNNDG], index=pd.Index(sPSSTNNDG))