openTEPES 4.18.8__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 CHANGED
@@ -14,7 +14,7 @@ Open Generation, Storage, and Transmission Operation and Expansion Planning Mode
14
14
  >>> import openTEPES as oT
15
15
  >>> oT.routine("9n", "C:\\Users\\UserName\\Documents\\GitHub\\openTEPES", "glpk")
16
16
  """
17
- __version__ = "4.18.8"
17
+ __version__ = "4.18.9"
18
18
 
19
19
  from .openTEPES_Main import main
20
20
  from .openTEPES import *
openTEPES/openTEPES.py CHANGED
@@ -1,5 +1,5 @@
1
1
  """
2
- Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - January 19, 2026
2
+ Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - January 22, 2026
3
3
  """
4
4
 
5
5
  # import dill as pickle
@@ -38,8 +38,8 @@ def openTEPES_run(DirName, CaseName, SolverName, pIndOutputResults, pIndLogConso
38
38
  idxDict['y' ] = 1
39
39
 
40
40
  #%% model declaration
41
- mTEPES = ConcreteModel('Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - Version 4.18.8 - January 19, 2026')
42
- print( 'Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - Version 4.18.8 - January 19, 2026', file=open(f'{_path}/openTEPES_version_{CaseName}.log','w'))
41
+ mTEPES = ConcreteModel('Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - Version 4.18.9 - January 22, 2026')
42
+ print( 'Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - Version 4.18.9 - January 22, 2026', file=open(f'{_path}/openTEPES_version_{CaseName}.log','w'))
43
43
 
44
44
  pIndOutputResults = [j for i,j in idxDict.items() if i == pIndOutputResults][0]
45
45
  pIndLogConsole = [j for i,j in idxDict.items() if i == pIndLogConsole ][0]
@@ -683,10 +683,10 @@ def DataConfiguration(mTEPES):
683
683
  mTEPES.psnnd = Set(initialize = [(p,sc,n,nd) for p,sc,n,nd in mTEPES.psn*mTEPES.nd ])
684
684
  mTEPES.psnar = Set(initialize = [(p,sc,n,ar) for p,sc,n,ar in mTEPES.psn*mTEPES.ar ])
685
685
 
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 ])
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 ])
690
690
 
691
691
  mTEPES.psnehc = Set(initialize = [(p,sc,n,eh) for p,sc,n,eh in mTEPES.psneh if mTEPES.dPar['pRatedMaxCharge'][eh] > 0.0 ])
692
692
 
@@ -660,7 +660,7 @@
660
660
  # For more information on this, and how to apply and follow the GNU AGPL, see
661
661
  # <https://www.gnu.org/licenses/>.
662
662
 
663
- # Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - January 19, 2026
663
+ # Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - January 22, 2026
664
664
  # simplicity and transparency in power systems planning
665
665
 
666
666
  # Developed by
@@ -693,7 +693,7 @@ GREEN = "\033[32m"
693
693
  BLUE = "\033[34m"
694
694
  RESET = "\033[0m"
695
695
 
696
- print(GREEN + 'Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - Version 4.18.8 - January 19, 2026' + RESET)
696
+ print(GREEN + 'Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - Version 4.18.9 - January 22, 2026' + RESET)
697
697
  print(BLUE + '#### Academic research license - for non-commercial use only ####' + RESET + '\n')
698
698
 
699
699
  parser = argparse.ArgumentParser(description='Introducing main parameters...')
@@ -1,5 +1,5 @@
1
1
  """
2
- Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - January 15, 2026
2
+ Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - January 22, 2026
3
3
  """
4
4
 
5
5
  import time
@@ -14,6 +14,7 @@ import plotly.io as pio
14
14
  import plotly.graph_objs as go
15
15
  from collections import defaultdict
16
16
  from colour import Color
17
+ import duckdb
17
18
 
18
19
  # from line_profiler import profile
19
20
 
@@ -34,12 +35,12 @@ def PiePlots(period, scenario, df, Category, Value):
34
35
  ComposedCategory = Category+':N'
35
36
  ComposedValue = Value +':Q'
36
37
 
37
- base = alt.Chart(OutputToPlot).encode(theta=alt.Theta(ComposedValue, type="quantitative", stack=True), color=alt.Color(ComposedCategory, scale=alt.Scale(scheme='category20c'), type="nominal", legend=alt.Legend(title=Category))).properties(width=800, height=800)
38
+ base = alt.Chart(OutputToPlot).encode(theta=alt.Theta(ComposedValue, type='quantitative', stack=True), color=alt.Color(ComposedCategory, scale=alt.Scale(scheme='category20c'), type='nominal', legend=alt.Legend(title=Category))).properties(width=800, height=800)
38
39
  pie = base.mark_arc(outerRadius=240)
39
40
  text = base.mark_text(radius=340, size=15).encode(text='Label:N')
40
41
  chart = pie+text
41
- # chart = chart.resolve_scale(theta="independent")
42
- chart = alt.layer(pie, text, data=OutputToPlot).resolve_scale(theta="independent")
42
+ # chart = chart.resolve_scale(theta='independent')
43
+ chart = alt.layer(pie, text, data=OutputToPlot).resolve_scale(theta='independent')
43
44
 
44
45
  return chart
45
46
 
@@ -103,6 +104,163 @@ def LinePlots(period, scenario, df, Category, X, Y, OperationType):
103
104
  return plot
104
105
 
105
106
 
107
+ def _set_df(con, name: str, df: pd.DataFrame):
108
+ """
109
+ Insert a pandas DataFrame into an existing DuckDB table.
110
+
111
+ Parameters
112
+ ----------
113
+ con : duckdb.DuckDBPyConnection
114
+ Open DuckDB connection.
115
+ name : str
116
+ Target table name.
117
+ df : pandas.DataFrame
118
+ DataFrame to insert into the target table.
119
+ """
120
+ con.cursor().execute(f"CREATE OR REPLACE TABLE '{name}' AS SELECT * FROM df;")
121
+
122
+
123
+ def _write_var_to_db(con, var, name):
124
+ """
125
+ Write a Pyomo Var's values and bounds to DuckDB.
126
+
127
+ Parameters
128
+ ----------
129
+ con : duckdb.DuckDBPyConnection
130
+ Open DuckDB connection.
131
+ var : pyomo.core.base.var.Var
132
+ Pyomo variable (indexed or scalar).
133
+ name : str
134
+ Variable/table name to use in the database.
135
+ """
136
+ values = var.extract_values()
137
+ s = pd.Series(values, index=values.keys())
138
+ df = s.to_frame(name=name).reset_index()
139
+ df = pd.concat(
140
+ [
141
+ df,
142
+ pd.DataFrame([dict(upper_bound=var[index].ub, lower_bound=var[index].lb) for index in var]),
143
+ ],
144
+ axis=1,
145
+ )
146
+ _set_df(con, f'v_{name}', df)
147
+
148
+
149
+ def _write_param_to_db(con, param, name):
150
+ """
151
+ Write a Pyomo Param's values to DuckDB.
152
+
153
+ Creates/inserts into a table named `{name}` with:
154
+ - the Param index (via reset_index)
155
+ - a column named `{name}` containing the Param value
156
+
157
+ Parameters
158
+ ----------
159
+ con : duckdb.DuckDBPyConnection
160
+ Open DuckDB connection.
161
+ param : pyomo.core.base.param.Param
162
+ Pyomo parameter (indexed or scalar).
163
+ name : str
164
+ Parameter/table name to use in the database.
165
+ """
166
+ values = param.extract_values()
167
+ s = pd.Series(values, index=values.keys())
168
+ df = s.to_frame(name=name).reset_index()
169
+ _set_df(con, f'p_{name}', df)
170
+
171
+
172
+ def _write_set_to_db(con, set_, name):
173
+ """
174
+ Write a Pyomo Set's elements to DuckDB.
175
+
176
+ Parameters
177
+ ----------
178
+ con : duckdb.DuckDBPyConnection
179
+ Open DuckDB connection.
180
+ set_ : pyomo.core.base.set.Set
181
+ Pyomo set.
182
+ name : str
183
+ Base name used to build the table name `s_{name}`.
184
+ """
185
+ s = pd.Series(set_.sorted_data())
186
+ df = s.to_frame(name=name).reset_index()
187
+ _set_df(con, f's_{name}', df)
188
+
189
+
190
+ def _write_constraint_to_db(con, constraint, name, model):
191
+ """
192
+ Write an indexed Pyomo Constraint's duals and bounds to DuckDB.
193
+
194
+ Parameters
195
+ ----------
196
+ con : duckdb.DuckDBPyConnection
197
+ Open DuckDB connection.
198
+ constraint : pyomo.core.base.constraint.Constraint
199
+ Pyomo constraint component (must be indexed; scalar constraints are skipped).
200
+ name : str
201
+ Constraint name used to build the table name `c_{name}`.
202
+ model : pyomo.core.base.PyomoModel.ConcreteModel
203
+ Model providing `pDuals` (mapping from constraint+index string to dual value).
204
+
205
+ Notes
206
+ -----
207
+ Non-indexed constraints are ignored
208
+ """
209
+ if not constraint.is_indexed():
210
+ return
211
+
212
+ records = []
213
+ for index in constraint:
214
+ key = str(constraint.name) + str(index)
215
+ records.append(
216
+ dict(
217
+ name=str(name),
218
+ index=index,
219
+ dual=model.pDuals.get(key),
220
+ lower_bound=constraint[index].lb,
221
+ upper_bound=constraint[index].ub,
222
+ )
223
+ )
224
+
225
+ df = pd.DataFrame(records)
226
+ _set_df(con, f'c_{name}', df.reset_index())
227
+
228
+
229
+ def write_model_to_db(model, filename):
230
+ """
231
+ Export Pyomo model components to a DuckDB database file.
232
+
233
+ Parameters
234
+ ----------
235
+ model : pyomo.core.base.PyomoModel.ConcreteModel
236
+ filename : str
237
+ """
238
+ with duckdb.connect(filename) as con:
239
+ model_vars = model.component_map(ctype=pyo.Var)
240
+ for k in model_vars.keys():
241
+ var = model_vars[k]
242
+ name = var.getname()
243
+ _write_var_to_db(con, var, name)
244
+
245
+ model_params = model.component_map(ctype=pyo.Param)
246
+ for k in model_params.keys():
247
+ param = model_params[k]
248
+ name = param.getname()
249
+ _write_param_to_db(con, param, name)
250
+
251
+ model_sets = model.component_map(ctype=pyo.Set)
252
+ for k in model_sets.keys():
253
+ s = model_sets[k]
254
+ name = s.getname()
255
+ _write_set_to_db(con, s, name)
256
+
257
+ model_constraints = model.component_map(ctype=pyo.Constraint)
258
+ for k in model_constraints.keys():
259
+ constraint = model_constraints[k]
260
+ name = k
261
+ _write_constraint_to_db(con, constraint, name, model)
262
+
263
+
106
264
  # write parameters, variables, and duals
107
265
  # @profile
108
266
  def OutputResultsParVarCon(DirName, CaseName, OptModel, mTEPES):
@@ -123,40 +281,42 @@ def OutputResultsParVarCon(DirName, CaseName, OptModel, mTEPES):
123
281
  os.makedirs(dump_folder)
124
282
  DateName = str(datetime.datetime.now().strftime('%Y%m%d'))
125
283
 
284
+ write_model_to_db(OptModel, f'{_path}/CaseDumpFolder_{CaseName}_{DateName}/oT_Case_{CaseName}.duckdb')
285
+
126
286
  # Extract and write parameters from the case
127
- with open(f'{_path}/CaseDumpFolder_{CaseName}_{DateName}/oT_Case_{CaseName}_Parameters.csv', 'w', newline='') as csvfile:
128
- writer = csv.writer(csvfile)
129
- writer.writerow(['Name', 'Index', 'Value'])
130
- for par in OptModel.component_objects(pyo.Param):
131
- par_object = getattr(OptModel, str(par))
132
- if par_object.is_indexed():
133
- for index in par_object:
134
- if (isinstance(index, tuple) and par_object.mutable == False) or par_object.mutable == False:
135
- writer.writerow([str(par), index, par_object[index]])
136
- else:
137
- writer.writerow([str(par), index, par_object[index].value])
138
- else:
139
- writer.writerow ([str(par), 'NA', par_object.value])
140
-
141
- # Extract and write variables
142
- with open(f'{_path}/CaseDumpFolder_{CaseName}_{DateName}/oT_Case_{CaseName}_Variables.csv', 'w', newline='') as csvfile:
143
- writer = csv.writer(csvfile)
144
- writer.writerow(['Name', 'Index', 'Value', 'Lower Bound', 'Upper Bound'])
145
- for var in OptModel.component_objects(pyo.Var, active=True):
146
- var_object = getattr(OptModel, str(var))
147
- for index in var_object:
148
- writer.writerow([str(var), index, var_object[index].value, str(var_object[index].lb), str(var_object[index].ub)])
149
-
150
- # Extract and write dual variables
151
- with open(f'{_path}/CaseDumpFolder_{CaseName}_{DateName}/oT_Case_{CaseName}_Constraints.csv', 'w', newline='') as csvfile:
152
- writer = csv.writer(csvfile)
153
- writer.writerow(['Name', 'Index', 'Value', 'Lower Bound', 'Upper Bound'])
154
- for con in OptModel.component_objects(pyo.Constraint, active=True):
155
- con_object = getattr(OptModel, str(con))
156
- if con.is_indexed():
157
- for index in con_object:
158
- writer.writerow([str(con), index, mTEPES.pDuals[str(con_object.name)+str(index)], str(con_object[index].lb), str(con_object[index].ub)])
159
- # writer.writerow([str(con), index, OptModel.dual[con_object[index]], str(con_object[index].lb), str(con_object[index].ub)])
287
+ # with open(f'{_path}/CaseDumpFolder_{CaseName}_{DateName}/oT_Case_{CaseName}_Parameters.csv', 'w', newline='') as csvfile:
288
+ # writer = csv.writer(csvfile)
289
+ # writer.writerow(['Name', 'Index', 'Value'])
290
+ # for par in OptModel.component_objects(pyo.Param):
291
+ # par_object = getattr(OptModel, str(par))
292
+ # if par_object.is_indexed():
293
+ # for index in par_object:
294
+ # if (isinstance(index, tuple) and par_object.mutable == False) or par_object.mutable == False:
295
+ # writer.writerow([str(par), index, par_object[index]])
296
+ # else:
297
+ # writer.writerow([str(par), index, par_object[index].value])
298
+ # else:
299
+ # writer.writerow ([str(par), 'NA', par_object.value])
300
+ #
301
+ # # Extract and write variables
302
+ # with open(f'{_path}/CaseDumpFolder_{CaseName}_{DateName}/oT_Case_{CaseName}_Variables.csv', 'w', newline='') as csvfile:
303
+ # writer = csv.writer(csvfile)
304
+ # writer.writerow(['Name', 'Index', 'Value', 'Lower Bound', 'Upper Bound'])
305
+ # for var in OptModel.component_objects(pyo.Var, active=True):
306
+ # var_object = getattr(OptModel, str(var))
307
+ # for index in var_object:
308
+ # writer.writerow([str(var), index, var_object[index].value, str(var_object[index].lb), str(var_object[index].ub)])
309
+ #
310
+ # # Extract and write dual variables
311
+ # with open(f'{_path}/CaseDumpFolder_{CaseName}_{DateName}/oT_Case_{CaseName}_Constraints.csv', 'w', newline='') as csvfile:
312
+ # writer = csv.writer(csvfile)
313
+ # writer.writerow(['Name', 'Index', 'Value', 'Lower Bound', 'Upper Bound'])
314
+ # for con in OptModel.component_objects(pyo.Constraint, active=True):
315
+ # con_object = getattr(OptModel, str(con))
316
+ # if con.is_indexed():
317
+ # for index in con_object:
318
+ # writer.writerow([str(con), index, mTEPES.pDuals[str(con_object.name)+str(index)], str(con_object[index].lb), str(con_object[index].ub)])
319
+ # # writer.writerow([str(con), index, OptModel.dual[con_object[index]], str(con_object[index].lb), str(con_object[index].ub)])
160
320
 
161
321
  # NameList = ['Parameters', 'Variables', 'Constraints']
162
322
  #
@@ -267,9 +427,9 @@ def InvestmentResults(DirName, CaseName, OptModel, mTEPES, pIndTechnologyOutput,
267
427
 
268
428
  MarketResultsInv = pd.concat([MarketResultsInv, OutputResults], axis=1)
269
429
 
270
- GenTechInvestCost = pd.Series(data=[sum(mTEPES.pDiscountedWeight[p] * mTEPES.pGenInvestCost[eb] * OptModel.vGenerationInvest[p,eb]() for eb in mTEPES.eb if eb in g2t[gt] ) for p,gt in mTEPES.p*mTEPES.gt], index=mTEPES.p*mTEPES.gt)
430
+ GenTechInvestCost = pd.Series(data=[sum(mTEPES.pDiscountedWeight[p] * mTEPES.pGenInvestCost[eb] * OptModel.vGenerationInvest[p,eb]() for eb in mTEPES.eb if eb in g2t[gt] and (p,eb) in mTEPES.peb ) for p,gt in mTEPES.p*mTEPES.gt], index=mTEPES.p*mTEPES.gt)
271
431
  GenTechInvestCost *= 1e3
272
- GenTechInjection = pd.Series(data=[sum(mTEPES.pDiscountedWeight[p] * mTEPES.pLoadLevelDuration[p,sc,n]() * OptModel.vTotalOutput[p,sc,n,eb]() for sc,n,eb in mTEPES.sc*mTEPES.n*mTEPES.eb if eb in g2t[gt] and (p,sc,n) in mTEPES.psn) for p,gt in mTEPES.p*mTEPES.gt], index=mTEPES.p*mTEPES.gt)
432
+ GenTechInjection = pd.Series(data=[sum(mTEPES.pDiscountedWeight[p] * mTEPES.pLoadLevelDuration[p,sc,n]() * OptModel.vTotalOutput[p,sc,n,eb]() for sc,n,eb in mTEPES.sc*mTEPES.n*mTEPES.eb if eb in g2t[gt] and (p,eb) in mTEPES.peb and (p,sc,n) in mTEPES.psn) for p,gt in mTEPES.p*mTEPES.gt], index=mTEPES.p*mTEPES.gt)
273
433
  GenTechInjection.name = 'Generation'
274
434
  MarketResultsInv = pd.concat([MarketResultsInv, GenTechInjection], axis=1)
275
435
  LCOE = GenTechInvestCost.div(GenTechInjection)
@@ -2227,24 +2387,24 @@ def EconomicResults(DirName, CaseName, OptModel, mTEPES, pIndAreaOutput, pIndPlo
2227
2387
  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]()
2228
2388
  OutputResults.to_csv(f'{_path}/oT_Result_CostSummary_{CaseName}_{ar}.csv', sep=',', index=False)
2229
2389
 
2230
- sPSSTNG = [(p,sc,st,n, g) for p,sc,st,n, g in mTEPES.s2n*mTEPES.g if (p,sc,n) in mTEPES.psn]
2390
+ sPSSTNG = [(p,sc,st,n, g) for p,sc,st,n, g in mTEPES.s2n*mTEPES.g if (p,sc,n) in mTEPES.psn and (p,g) in mTEPES.pg]
2231
2391
  sPSSTNND = [(p,sc,st,n,nd ) for p,sc,st,n,nd in mTEPES.s2n*mTEPES.nd if sum(1 for g in g2n[nd]) + sum(1 for nf,cc in lout[nd]) + sum(1 for ni,cc in lin[nd]) and (p,sc,n) in mTEPES.psn]
2232
2392
  sPSSTNNDG = [(p,sc,st,n,nd,g) for p,sc,st,n,nd,g in sPSSTNND*mTEPES.g if (nd,g) in mTEPES.n2g and (p,g) in mTEPES.pg]
2233
- OutputResults = pd.Series(data=[ mTEPES.pDuals["".join([f"eBalanceElec_{p}_{sc}_{st}('{n}', '{nd}')"])]/mTEPES.pPeriodProb[p,sc]()/mTEPES.pLoadLevelDuration[p,sc,n]()*OptModel.vTotalOutput [p,sc,n,g]() for p,sc,st,n,nd,g in sPSSTNNDG], index=pd.Index(sPSSTNNDG))
2234
- MeanOutput = pd.Series(data=[ OptModel.vTotalOutput [p,sc,n,g]() for p,sc,st,n, g in sPSSTNG ], index=pd.Index(sPSSTNG )).groupby(level=4).mean()
2393
+ OutputResults = pd.Series(data=[ mTEPES.pDuals["".join([f"eBalanceElec_{p}_{sc}_{st}('{n}', '{nd}')"])]/mTEPES.pPeriodProb[p,sc]()/mTEPES.pLoadLevelDuration[p,sc,n]()*OptModel.vTotalOutput [p,sc,n,g]() for p,sc,st,n,nd,g in sPSSTNNDG if (p,g) in mTEPES.pg], index=pd.Index(sPSSTNNDG))
2394
+ MeanOutput = pd.Series(data=[ OptModel.vTotalOutput [p,sc,n,g]() for p,sc,st,n, g in sPSSTNG if (p,g) in mTEPES.pg], index=pd.Index(sPSSTNG )).groupby(level=4).mean()
2235
2395
  MeanOutput *= 1e-3
2236
2396
  OutputResults.to_frame(name='MEUR').reset_index().pivot_table(index=['level_0','level_1','level_3'], columns='level_5', values='MEUR').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).to_csv(f'{_path}/oT_Result_RevenueEnergyGeneration_{CaseName}.csv', sep=',')
2237
2397
  OutputResults = pd.Series(data=[ mTEPES.pDuals["".join([f"eBalanceElec_{p}_{sc}_{st}('{n}', '{nd}')"])]/mTEPES.pPeriodProb[p,sc]()/mTEPES.pLoadLevelDuration[p,sc,n]()*OptModel.vTotalOutput [p,sc,n,g]()/MeanOutput[g] for p,sc,st,n,nd,g in sPSSTNNDG], index=pd.Index(sPSSTNNDG))
2238
2398
  OutputResults.to_frame(name='EUR/MWh').reset_index().pivot_table(index=['level_0','level_1','level_3'], columns='level_5', values='EUR/MWh').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).to_csv(f'{_path}/oT_Result_GenerationCapturedSRMC_{CaseName}.csv', sep=',')
2239
2399
 
2240
2400
  if mTEPES.eh:
2241
- sPSSTNES = [(p,sc,st,n, eh) for p,sc,st,n, eh in mTEPES.s2n*mTEPES.eh if (p,sc,n) in mTEPES.psn]
2242
- sPSSTNNDEH = [(p,sc,st,n,nd,eh) for p,sc,st,n,nd,eh in sPSSTNND*mTEPES.eh if (nd,eh) in mTEPES.n2g and (p,eh) in mTEPES.peh]
2243
- OutputResults = pd.Series(data=[-mTEPES.pDuals["".join([f"eBalanceElec_{p}_{sc}_{st}('{n}', '{nd}')"])]/mTEPES.pPeriodProb[p,sc]()/mTEPES.pLoadLevelDuration[p,sc,n]()*OptModel.vESSTotalCharge[p,sc,n,eh]() for p,sc,st,n,nd,eh in sPSSTNNDEH], index=pd.Index(sPSSTNNDEH))
2244
- MeanOutput = pd.Series(data=[ OptModel.vESSTotalCharge[p,sc,n,eh]() for p,sc,st,n, eh in sPSSTNES ], index=pd.Index(sPSSTNES )).groupby(level=4).mean()
2401
+ sPSSTNES = [(p,sc,st,n, eh) for p,sc,st,n, eh in mTEPES.s2n*mTEPES.eh if (p,sc,n) in mTEPES.psn and (p,eh) in mTEPES.peh]
2402
+ sPSSTNNDEH = [(p,sc,st,n,nd,eh) for p,sc,st,n,nd,eh in sPSSTNND*mTEPES.eh if (nd,eh) in mTEPES.n2g and (p,eh) in mTEPES.peh]
2403
+ OutputResults = pd.Series(data=[-mTEPES.pDuals["".join([f"eBalanceElec_{p}_{sc}_{st}('{n}', '{nd}')"])]/mTEPES.pPeriodProb[p,sc]()/mTEPES.pLoadLevelDuration[p,sc,n]()*OptModel.vESSTotalCharge[p,sc,n,eh]() for p,sc,st,n,nd,eh in sPSSTNNDEH if (p,eh) in mTEPES.peh], index=pd.Index(sPSSTNNDEH))
2404
+ MeanOutput = pd.Series(data=[ OptModel.vESSTotalCharge[p,sc,n,eh]() for p,sc,st,n, eh in sPSSTNES if (p,eh) in mTEPES.peh], index=pd.Index(sPSSTNES )).groupby(level=4).mean()
2245
2405
  MeanOutput *= 1e-3
2246
2406
  OutputResults.to_frame(name='MEUR').reset_index().pivot_table(index=['level_0','level_1','level_3'], columns='level_5', values='MEUR').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).to_csv(f'{_path}/oT_Result_RevenueEnergyConsumption_{CaseName}.csv', sep=',')
2247
- OutputResults = pd.Series(data=[-mTEPES.pDuals["".join([f"eBalanceElec_{p}_{sc}_{st}('{n}', '{nd}')"])]/mTEPES.pPeriodProb[p,sc]()/mTEPES.pLoadLevelDuration[p,sc,n]()*OptModel.vESSTotalCharge[p,sc,n,eh]()/MeanOutput[eh] for p,sc,st,n,nd,eh in sPSSTNNDEH], index=pd.Index(sPSSTNNDEH))
2407
+ OutputResults = pd.Series(data=[-mTEPES.pDuals["".join([f"eBalanceElec_{p}_{sc}_{st}('{n}', '{nd}')"])]/mTEPES.pPeriodProb[p,sc]()/mTEPES.pLoadLevelDuration[p,sc,n]()*OptModel.vESSTotalCharge[p,sc,n,eh]()/MeanOutput[eh] for p,sc,st,n,nd,eh in sPSSTNNDEH if (p,eh) in mTEPES.peh], index=pd.Index(sPSSTNNDEH))
2248
2408
  OutputResults.to_frame(name='EUR/MWh').reset_index().pivot_table(index=['level_0','level_1','level_3'], columns='level_5', values='EUR/MWh').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).to_csv(f'{_path}/oT_Result_ConsumptionCapturedSRMC_{CaseName}.csv', sep=',')
2249
2409
 
2250
2410
  if mTEPES.gc:
@@ -2253,16 +2413,16 @@ def EconomicResults(DirName, CaseName, OptModel, mTEPES, pIndAreaOutput, pIndPlo
2253
2413
  sPSSTNNDGC1 = [(p,sc,st,n,nd,gc) for p,sc,st,n,nd,gc in mTEPES.s2n*mTEPES.n2g if gc in mTEPES.gc if (p,gc) in mTEPES.pgc and (p,sc,n) in mTEPES.psn]
2254
2414
  OutputToGenRev = pd.Series(data=[mTEPES.pDuals["".join([f"eBalanceElec_{p}_{sc}_{st}('{n}', '{nd}')"])]/mTEPES.pPeriodProb[p,sc]()/mTEPES.pLoadLevelDuration[p,sc,n]()*OptModel.vTotalOutput [p,sc,n,gc]() for p,sc,st,n,nd,gc in sPSSTNNDGC1], index=pd.Index(sPSSTNNDGC1))
2255
2415
  GenRev.append(OutputToGenRev)
2256
- if len([(p,sc,n,nd,gc) for p,sc,n,nd,gc in mTEPES.psn*mTEPES.n2g if gc in mTEPES.gc for ot in mTEPES.ot if (p,gc) in mTEPES.pgc and gc in o2e[ot]]):
2257
- sPSSTNNDGC2 = [(p,sc,st,n,nd,gc) for p,sc,st,n,nd,gc in sPSSTNNDGC1 for ot in mTEPES.ot if (p,gc) in mTEPES.pgc and gc in o2e[ot] and (p,sc,n) in mTEPES.psn]
2416
+ if len([(p,sc,n,nd,gc) for p,sc, n,nd,gc in mTEPES.psn*mTEPES.n2g if gc in mTEPES.gc for ot in mTEPES.ot if (p,sc,n) in mTEPES.psn and (p,gc) in mTEPES.pgc and gc in o2e[ot]]):
2417
+ sPSSTNNDGC2 = [(p,sc,st,n,nd,gc) for p,sc,st,n,nd,gc in sPSSTNNDGC1 for ot in mTEPES.ot if (p,sc,n) in mTEPES.psn and (p,gc) in mTEPES.pgc and gc in o2e[ot]]
2258
2418
  OutputChargeRevESS = pd.Series(data=[mTEPES.pDuals["".join([f"eBalanceElec_{p}_{sc}_{st}('{n}', '{nd}')"])]/mTEPES.pPeriodProb[p,sc]()/mTEPES.pLoadLevelDuration[p,sc,n]()*OptModel.vESSTotalCharge[p,sc,n,gc]() for p,sc,st,n,nd,gc in sPSSTNNDGC2], index=pd.Index(sPSSTNNDGC2))
2259
2419
  ChargeRev.append(OutputChargeRevESS)
2260
- if len([(p,sc,n,nd,gc) for p,sc,n,nd,gc in mTEPES.psn*mTEPES.n2g if gc in mTEPES.gc for rt in mTEPES.rt if (p,gc) in mTEPES.pgc and gc in r2r[rt]]):
2261
- sPSSTNNDGC3 = [(p,sc,st,n,nd,gc) for p,sc,st,n,nd,gc in sPSSTNNDGC1 for rt in mTEPES.rt if (p,gc) in mTEPES.pgc and gc in r2r[rt] and (p,sc,n) in mTEPES.psn]
2420
+ if len([(p,sc,n,nd,gc) for p,sc, n,nd,gc in mTEPES.psn*mTEPES.n2g if gc in mTEPES.gc for rt in mTEPES.rt if (p,sc,n) in mTEPES.psn and (p,gc) in mTEPES.pgc and gc in r2r[rt]]):
2421
+ sPSSTNNDGC3 = [(p,sc,st,n,nd,gc) for p,sc,st,n,nd,gc in sPSSTNNDGC1 for rt in mTEPES.rt if (p,sc,n) in mTEPES.psn and (p,gc) in mTEPES.pgc and gc in r2r[rt]]
2262
2422
  OutputChargeRevRES = pd.Series(data=[mTEPES.pDuals["".join([f"eBalanceElec_{p}_{sc}_{st}('{n}', '{nd}')"])]/mTEPES.pPeriodProb[p,sc]()/mTEPES.pLoadLevelDuration[p,sc,n]() * 0.0 for p,sc,st,n,nd,gc in sPSSTNNDGC3], index=pd.Index(sPSSTNNDGC3))
2263
2423
  ChargeRev.append(OutputChargeRevRES)
2264
- if len([(p,sc,n,nd,gc) for p,sc,n,nd,gc in mTEPES.psn*mTEPES.n2g if gc in mTEPES.gc for ot in mTEPES.ot if (p,gc) in mTEPES.pgc and gc in o2e[ot]]):
2265
- sPSSTNNDGC4 = [(p,sc,st,n,nd,gc) for p,sc,st,n,nd,gc in sPSSTNNDGC1 for ot in mTEPES.ot if (p,gc) in mTEPES.pgc and gc in o2e[ot] and (p,sc,n) in mTEPES.psn]
2424
+ if len([(p,sc,n,nd,gc) for p,sc, n,nd,gc in mTEPES.psn*mTEPES.n2g if gc in mTEPES.gc for ot in mTEPES.ot if (p,sc,n) in mTEPES.psn and (p,gc) in mTEPES.pgc and gc in o2e[ot]]):
2425
+ sPSSTNNDGC4 = [(p,sc,st,n,nd,gc) for p,sc,st,n,nd,gc in sPSSTNNDGC1 for ot in mTEPES.ot if (p,sc,n) in mTEPES.psn and (p,gc) in mTEPES.pgc and gc in o2e[ot]]
2266
2426
  OutputChargeRevThr = pd.Series(data=[mTEPES.pDuals["".join([f"eBalanceElec_{p}_{sc}_{st}('{n}', '{nd}')"])]/mTEPES.pPeriodProb[p,sc]()/mTEPES.pLoadLevelDuration[p,sc,n]() * 0.0 for p,sc,st,n,nd,gc in sPSSTNNDGC4], index=pd.Index(sPSSTNNDGC4))
2267
2427
  ChargeRev.append(OutputChargeRevThr)
2268
2428
  if len(GenRev):
@@ -2284,7 +2444,7 @@ def EconomicResults(DirName, CaseName, OptModel, mTEPES, pIndAreaOutput, pIndPlo
2284
2444
 
2285
2445
  if sum(mTEPES.pReserveMargin[:,:]):
2286
2446
  if mTEPES.gc:
2287
- sPSSTARGC = [(p,sc,st,ar,gc) for p,sc,st,ar,gc in mTEPES.ps*mTEPES.st*mTEPES.ar*mTEPES.gc if gc in g2a[ar] and mTEPES.pReserveMargin[p,ar] and st == mTEPES.Last_st and sum(1 for gc in mTEPES.gc if gc in g2a[ar]) and sum(mTEPES.pRatedMaxPowerElec[g] * mTEPES.pAvailability[g]() / (1.0-mTEPES.pEFOR[g]) for g in mTEPES.g if g in g2a[ar] and g not in (mTEPES.gc or mTEPES.gd)) <= mTEPES.pDemandElecPeak[p,ar] * mTEPES.pReserveMargin[p,ar]]
2447
+ sPSSTARGC = [(p,sc,st,ar,gc) for p,sc,st,ar,gc in mTEPES.ps*mTEPES.st*mTEPES.ar*mTEPES.gc if gc in g2a[ar] and (p,gc) in mTEPES.pgc and mTEPES.pReserveMargin[p,ar] and st == mTEPES.Last_st and sum(1 for gc in mTEPES.gc if gc in g2a[ar]) and sum(mTEPES.pRatedMaxPowerElec[g] * mTEPES.pAvailability[g]() / (1.0-mTEPES.pEFOR[g]) for g in mTEPES.g if g in g2a[ar] and g not in (mTEPES.gc or mTEPES.gd)) <= mTEPES.pDemandElecPeak[p,ar] * mTEPES.pReserveMargin[p,ar]]
2288
2448
  OutputToResRev = pd.Series(data=[mTEPES.pDuals[''.join([f'eAdequacyReserveMarginElec_{p}_{sc}_{st}{ar}'])]*mTEPES.pRatedMaxPowerElec[gc]*mTEPES.pAvailability[gc]() for p,sc,st,ar,gc in sPSSTARGC], index=pd.Index(sPSSTARGC))
2289
2449
  ResRev = pd.Series(data=[0.0 for gc in mTEPES.gc], index=mTEPES.gc, dtype='float64')
2290
2450
  if sPSSTARGC:
@@ -2296,18 +2456,18 @@ def EconomicResults(DirName, CaseName, OptModel, mTEPES, pIndAreaOutput, pIndPlo
2296
2456
  ResRev = pd.Series(data=[0.0 for gc in mTEPES.gc], index=mTEPES.gc, dtype='float64')
2297
2457
 
2298
2458
  if sum(mTEPES.pOperReserveUp[:,:,:,:]) and sum(1 for ar,nr in mTEPES.ar*mTEPES.nr if nr in g2a[ar] and (mTEPES.pIndOperReserveGen[nr] == 0 or mTEPES.pIndOperReserveCon[nr] == 0)) + sum(1 for ar,es in mTEPES.ar*mTEPES.es if es in g2a[ar] and (mTEPES.pIndOperReserveGen[nr] == 0 or mTEPES.pIndOperReserveCon[nr] == 0)):
2299
- if len([(p,sc,n,ar,nr) for p,sc,n,ar,nr in mTEPES.psn*mTEPES.ar*mTEPES.nr if nr in g2a[ar] and mTEPES.pOperReserveUp[p,sc,n,ar] and (p,sc,n,nr) in mTEPES.psnnr]):
2300
- sPSSTNARNR = [(p,sc,st,n,ar,nr) for p,sc,st,n,ar,nr in mTEPES.s2n*mTEPES.ar*mTEPES.nr if nr in g2a[ar] and mTEPES.pOperReserveUp[p,sc,n,ar] and (p,sc,n,nr) in mTEPES.psnnr]
2459
+ if len([(p,sc,n,ar,nr) for p,sc, n,ar,nr in mTEPES.psn*mTEPES.ar*mTEPES.nr if nr in g2a[ar] and mTEPES.pOperReserveUp[p,sc,n,ar] and (p,sc,n,nr) in mTEPES.psnnr and (p,nr) in mTEPES.pnr]):
2460
+ sPSSTNARNR = [(p,sc,st,n,ar,nr) for p,sc,st,n,ar,nr in mTEPES.s2n*mTEPES.ar*mTEPES.nr if nr in g2a[ar] and mTEPES.pOperReserveUp[p,sc,n,ar] and (p,sc,n,nr) in mTEPES.psnnr and (p,nr) in mTEPES.pnr]
2301
2461
  OutputResults = pd.Series(data=[mTEPES.pDuals["".join([f"eOperReserveUp_{p}_{sc}_{st}('{n}', '{ar}')"])]/mTEPES.pPeriodProb[p,sc]()*OptModel.vReserveUp [p,sc,n,nr]() for p,sc,st,n,ar,nr in sPSSTNARNR], index=pd.Index(sPSSTNARNR))
2302
2462
  OutputResults.to_frame(name='MEUR').reset_index().pivot_table(index=['level_0','level_1','level_3'], columns='level_5', values='MEUR').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).to_csv(f'{_path}/oT_Result_RevenueOperatingReserveUp_{CaseName}.csv', sep=',')
2303
2463
 
2304
- if len([(p,sc,n,ar,eh) for p,sc,n,ar,eh in mTEPES.psn*mTEPES.ar*mTEPES.eh if eh in g2a[ar] and mTEPES.pOperReserveUp[p,sc,n,ar] and (p,sc,n,eh) in mTEPES.psnehc]):
2305
- sPSSTNARES = [(p,sc,st,n,ar,eh) for p,sc,st,n,ar,eh in mTEPES.s2n*mTEPES.ar*mTEPES.eh if eh in g2a[ar] and mTEPES.pOperReserveUp[p,sc,n,ar] and (p,sc,n,eh) in mTEPES.psnehc]
2464
+ if len([(p,sc,n,ar,eh) for p,sc, n,ar,eh in mTEPES.psn*mTEPES.ar*mTEPES.eh if eh in g2a[ar] and mTEPES.pOperReserveUp[p,sc,n,ar] and (p,sc,n,eh) in mTEPES.psnehc and (p,eh) in mTEPES.peh]):
2465
+ sPSSTNARES = [(p,sc,st,n,ar,eh) for p,sc,st,n,ar,eh in mTEPES.s2n*mTEPES.ar*mTEPES.eh if eh in g2a[ar] and mTEPES.pOperReserveUp[p,sc,n,ar] and (p,sc,n,eh) in mTEPES.psnehc and (p,eh) in mTEPES.peh]
2306
2466
  OutputResults = pd.Series(data=[mTEPES.pDuals["".join([f"eOperReserveUp_{p}_{sc}_{st}('{n}', '{ar}')"])]/mTEPES.pPeriodProb[p,sc]()*OptModel.vESSReserveUp[p,sc,n,eh]() for p,sc,st,n,ar,eh in sPSSTNARES], index=pd.Index(sPSSTNARES))
2307
2467
  OutputResults.to_frame(name='MEUR').reset_index().pivot_table(index=['level_0','level_1','level_3'], columns='level_5', values='MEUR').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).to_csv(f'{_path}/oT_Result_RevenueOperatingReserveUpESS_{CaseName}.csv', sep=',')
2308
2468
 
2309
- if len([(p,sc,n,ar,ec) for p,sc,n,ar,ec in mTEPES.psn*mTEPES.ar*mTEPES.gc if ec in g2a[ar] and mTEPES.pOperReserveUp[p,sc,n,ar] and (p,sc,n,ec) in mTEPES.psnec]):
2310
- sPSSTNAREC = [(p,sc,st,n,ar,ec) for p,sc,st,n,ar,ec in mTEPES.s2n*mTEPES.ar*mTEPES.ec if ec in g2a[ar] and mTEPES.pOperReserveUp[p,sc,n,ar] and (p,sc,n,ec) in mTEPES.psnec]
2469
+ if len([(p,sc,n,ar,ec) for p,sc, n,ar,ec in mTEPES.psn*mTEPES.ar*mTEPES.gc if ec in g2a[ar] and mTEPES.pOperReserveUp[p,sc,n,ar] and (p,sc,n,ec) in mTEPES.psnec and (p,ec) in mTEPES.pec]):
2470
+ sPSSTNAREC = [(p,sc,st,n,ar,ec) for p,sc,st,n,ar,ec in mTEPES.s2n*mTEPES.ar*mTEPES.ec if ec in g2a[ar] and mTEPES.pOperReserveUp[p,sc,n,ar] and (p,sc,n,ec) in mTEPES.psnec and (p,ec) in mTEPES.pec]
2311
2471
  OutputResults = pd.Series(data=[mTEPES.pDuals["".join([f"eOperReserveUp_{p}_{sc}_{st}('{n}', '{ar}')"])]/mTEPES.pPeriodProb[p,sc]()*(OptModel.vReserveUp[p,sc,n,ec]()+OptModel.vESSReserveUp[p,sc,n,ec]()) for p,sc,st,n,ar,ec in sPSSTNAREC], index=pd.Index(sPSSTNAREC), dtype='float64')
2312
2472
  if len(OutputResults):
2313
2473
  OutputToUpRev = OutputResults.to_frame('MEUR').reset_index().pivot_table(index=['level_0','level_1','level_3'], columns='level_5', values='MEUR').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).sum(axis=0)
@@ -2323,18 +2483,18 @@ def EconomicResults(DirName, CaseName, OptModel, mTEPES, pIndAreaOutput, pIndPlo
2323
2483
  UpRev = pd.Series(data=[0.0 for gc in mTEPES.gc], index=mTEPES.gc, dtype='float64')
2324
2484
 
2325
2485
  if sum(mTEPES.pOperReserveDw[:,:,:,:]) and sum(1 for ar,nr in mTEPES.ar*mTEPES.nr if nr in g2a[ar] and (mTEPES.pIndOperReserveGen[nr] == 0 or mTEPES.pIndOperReserveGen[nr] == 0 )) + sum(1 for ar,es in mTEPES.ar*mTEPES.es if es in g2a[ar] and (mTEPES.pIndOperReserveGen[es] == 0 or mTEPES.pIndOperReserveCon[es] == 0 )):
2326
- if len([(p,sc,n,ar,nr) for p,sc,n,ar,nr in mTEPES.psn*mTEPES.ar*mTEPES.nr if nr in g2a[ar] and mTEPES.pOperReserveDw[p,sc,n,ar] and (p,sc,n,nr) in mTEPES.psnnr]):
2327
- sPSSTNARNR = [(p,sc,st,n,ar,nr) for p,sc,st,n,ar,nr in mTEPES.s2n*mTEPES.ar*mTEPES.nr if nr in g2a[ar] and mTEPES.pOperReserveDw[p,sc,n,ar] and (p,sc,n,nr) in mTEPES.psnnr]
2486
+ if len([(p,sc,n,ar,nr) for p,sc, n,ar,nr in mTEPES.psn*mTEPES.ar*mTEPES.nr if nr in g2a[ar] and mTEPES.pOperReserveDw[p,sc,n,ar] and (p,sc,n,nr) in mTEPES.psnnr and (p,nr) in mTEPES.pnr]):
2487
+ sPSSTNARNR = [(p,sc,st,n,ar,nr) for p,sc,st,n,ar,nr in mTEPES.s2n*mTEPES.ar*mTEPES.nr if nr in g2a[ar] and mTEPES.pOperReserveDw[p,sc,n,ar] and (p,sc,n,nr) in mTEPES.psnnr and (p,nr) in mTEPES.pnr]
2328
2488
  OutputResults = pd.Series(data=[mTEPES.pDuals["".join([f"eOperReserveDw_{p}_{sc}_{st}('{n}', '{ar}')"])]/mTEPES.pPeriodProb[p,sc]()*OptModel.vReserveDown [p,sc,n,nr]() for p,sc,st,n,ar,nr in sPSSTNARNR], index=pd.Index(sPSSTNARNR))
2329
2489
  OutputResults.to_frame(name='MEUR').reset_index().pivot_table(index=['level_0','level_1','level_3'], columns='level_5', values='MEUR').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).to_csv(f'{_path}/oT_Result_RevenueOperatingReserveDw_{CaseName}.csv', sep=',')
2330
2490
 
2331
- if len([(p,sc,n,ar,eh) for p,sc,n,ar,eh in mTEPES.psn*mTEPES.ar*mTEPES.eh if eh in g2a[ar] if mTEPES.pOperReserveDw[p,sc,n,ar] and (p,sc,n,eh) in mTEPES.psnehc]):
2332
- sPSSTNARES = [(p,sc,st,n,ar,eh) for p,sc,st,n,ar,eh in mTEPES.s2n*mTEPES.ar*mTEPES.eh if eh in g2a[ar] and mTEPES.pOperReserveDw[p,sc,n,ar] and (p,sc,n,eh) in mTEPES.psnehc]
2491
+ if len([(p,sc,n,ar,eh) for p,sc, n,ar,eh in mTEPES.psn*mTEPES.ar*mTEPES.eh if eh in g2a[ar] and mTEPES.pOperReserveDw[p,sc,n,ar] and (p,sc,n,eh) in mTEPES.psnehc and (p,eh) in mTEPES.peh]):
2492
+ sPSSTNARES = [(p,sc,st,n,ar,eh) for p,sc,st,n,ar,eh in mTEPES.s2n*mTEPES.ar*mTEPES.eh if eh in g2a[ar] and mTEPES.pOperReserveDw[p,sc,n,ar] and (p,sc,n,eh) in mTEPES.psnehc and (p,eh) in mTEPES.peh]
2333
2493
  OutputResults = pd.Series(data=[mTEPES.pDuals["".join([f"eOperReserveDw_{p}_{sc}_{st}('{n}', '{ar}')"])]/mTEPES.pPeriodProb[p,sc]()*OptModel.vESSReserveDown[p,sc,n,eh]() for p,sc,st,n,ar,eh in sPSSTNARES], index=pd.Index(sPSSTNARES))
2334
2494
  OutputResults.to_frame(name='MEUR').reset_index().pivot_table(index=['level_0','level_1','level_3'], columns='level_5', values='MEUR').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).to_csv(f'{_path}/oT_Result_RevenueOperatingReserveDwESS_{CaseName}.csv', sep=',')
2335
2495
 
2336
- if len([(p,sc,n,ar,ec) for p,sc,n,ar,ec in mTEPES.psn*mTEPES.ar*mTEPES.ec if ec in g2a[ar] if mTEPES.pOperReserveDw[p,sc,n,ar] and (p,sc,n,ec) in mTEPES.psnec]):
2337
- sPSSTNAREC = [(p,sc,st,n,ar,ec) for p,sc,st,n,ar,ec in mTEPES.s2n*mTEPES.ar*mTEPES.ec if ec in g2a[ar] and mTEPES.pOperReserveDw[p,sc,n,ar] and (p,sc,n,ec) in mTEPES.psnec]
2496
+ if len([(p,sc,n,ar,ec) for p,sc, n,ar,ec in mTEPES.psn*mTEPES.ar*mTEPES.ec if ec in g2a[ar] and mTEPES.pOperReserveDw[p,sc,n,ar] and (p,sc,n,ec) in mTEPES.psnec and (p,ec) in mTEPES.pec]):
2497
+ sPSSTNAREC = [(p,sc,st,n,ar,ec) for p,sc,st,n,ar,ec in mTEPES.s2n*mTEPES.ar*mTEPES.ec if ec in g2a[ar] and mTEPES.pOperReserveDw[p,sc,n,ar] and (p,sc,n,ec) in mTEPES.psnec and (p,ec) in mTEPES.pec]
2338
2498
  OutputResults = pd.Series(data=[mTEPES.pDuals["".join([f"eOperReserveDw_{p}_{sc}_{st}('{n}', '{ar}')"])]/mTEPES.pPeriodProb[p,sc]()*(OptModel.vReserveDown[p,sc,n,ec]()+OptModel.vESSReserveDown[p,sc,n,ec]()) for p,sc,st,n,ar,ec in sPSSTNAREC], index=pd.Index(sPSSTNAREC), dtype='float64')
2339
2499
  if len(OutputResults):
2340
2500
  OutputToDwRev = OutputResults.to_frame('MEUR').reset_index().pivot_table(index=['level_0','level_1','level_3'], columns='level_5', values='MEUR').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).sum(axis=0)
@@ -2349,18 +2509,18 @@ def EconomicResults(DirName, CaseName, OptModel, mTEPES, pIndAreaOutput, pIndPlo
2349
2509
  DwRev = pd.Series(data=[0.0 for gc in mTEPES.gc], index=mTEPES.gc, dtype='float64')
2350
2510
 
2351
2511
  if mTEPES.pIndRampReserves == 1 and sum(mTEPES.pRampReserveUp[:,:,:,:]):
2352
- if len([(p,sc,n,nr) for p,sc,n,nr in mTEPES.psn*mTEPES.nr if sum(mTEPES.pRampReserveUp[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,nr) in mTEPES.psnnr]):
2353
- sPSSTNNR = [(p,sc,st,n,nr) for p,sc,st,n,nr in mTEPES.s2n*mTEPES.nr if sum(mTEPES.pRampReserveUp[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,nr) in mTEPES.psnnr]
2512
+ if len([(p,sc,n,nr) for p,sc, n,nr in mTEPES.psn*mTEPES.nr if sum(mTEPES.pRampReserveUp[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,nr) in mTEPES.psnnr and (p,nr) in mTEPES.pnr]):
2513
+ sPSSTNNR = [(p,sc,st,n,nr) for p,sc,st,n,nr in mTEPES.s2n*mTEPES.nr if sum(mTEPES.pRampReserveUp[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,nr) in mTEPES.psnnr and (p,nr) in mTEPES.pnr]
2354
2514
  OutputResults = pd.Series(data=[mTEPES.pDuals["".join([f"eSystemRampUp_{p}_{sc}_{st}{n}"])]/mTEPES.pPeriodProb[p,sc]()*OptModel.vRampReserveUp[p,sc,n,nr]() for p,sc,st,n,nr in sPSSTNNR], index=pd.Index(sPSSTNNR))
2355
2515
  OutputResults.to_frame(name='MEUR').reset_index().pivot_table(index=['level_0','level_1','level_3'], columns='level_4', values='MEUR').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).to_csv(f'{_path}/oT_Result_RevenueRampReserveUp_{CaseName}.csv', sep=',')
2356
2516
 
2357
- # if len([(p,sc,n,eh) for p,sc,n,eh in mTEPES.psn*mTEPES.eh if sum(mTEPES.pRampReserveUp[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,eh) in mTEPES.psnehc]):
2358
- # sPSSTNES = [(p,sc,st,n,eh) for p,sc,st,n,eh in mTEPES.s2n*mTEPES.eh if sum(mTEPES.pRampReserveUp[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,eh) in mTEPES.psnehc]
2517
+ # if len([(p,sc,n,eh) for p,sc, n,eh in mTEPES.psn*mTEPES.eh if sum(mTEPES.pRampReserveUp[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,eh) in mTEPES.psnehc and (p,eh) in mTEPES.peh]):
2518
+ # sPSSTNES = [(p,sc,st,n,eh) for p,sc,st,n,eh in mTEPES.s2n*mTEPES.eh if sum(mTEPES.pRampReserveUp[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,eh) in mTEPES.psnehc and (p,eh) in mTEPES.peh]
2359
2519
  # OutputResults = pd.Series(data=[mTEPES.pDuals["".join([f"eSystemRampUp_{p}_{sc}_{st}{n}"])]/mTEPES.pPeriodProb[p,sc]()*OptModel.vRampReserveUp[p,sc,n,eh]() for p,sc,st,n,eh in sPSSTNES], index=pd.Index(sPSSTNES))
2360
2520
  # OutputResults.to_frame(name='MEUR').reset_index().pivot_table(index=['level_0','level_1','level_3'], columns='level_4', values='MEUR').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).to_csv(f'{_path}/oT_Result_RevenueRampReserveUpESS_{CaseName}.csv', sep=',')
2361
2521
 
2362
- if len([(p,sc,n,ec) for p,sc,n,ec in mTEPES.psn*mTEPES.gc if sum(mTEPES.pRampReserveUp[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,ec) in mTEPES.psnec]):
2363
- sPSSTNEC = [(p,sc,st,n,ec) for p,sc,st,n,ec in mTEPES.s2n*mTEPES.ec if sum(mTEPES.pRampReserveUp[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,ec) in mTEPES.psnec]
2522
+ if len([(p,sc,n,ec) for p,sc, n,ec in mTEPES.psn*mTEPES.gc if sum(mTEPES.pRampReserveUp[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,ec) in mTEPES.psnec and (p,ec) in mTEPES.pec]):
2523
+ sPSSTNEC = [(p,sc,st,n,ec) for p,sc,st,n,ec in mTEPES.s2n*mTEPES.ec if sum(mTEPES.pRampReserveUp[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,ec) in mTEPES.psnec and (p,ec) in mTEPES.pec]
2364
2524
  OutputResults = pd.Series(data=[mTEPES.pDuals["".join([f"eSystemRampUp_{p}_{sc}_{st}{n}"])]/mTEPES.pPeriodProb[p,sc]()*OptModel.vRampReserveUp[p,sc,n,ec]() for p,sc,st,n,ec in sPSSTNEC], index=pd.Index(sPSSTNEC), dtype='float64')
2365
2525
  if len(OutputResults):
2366
2526
  OutputToUpRev = OutputResults.to_frame('MEUR').reset_index().pivot_table(index=['level_0','level_1','level_3'], columns='level_4', values='MEUR').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).sum(axis=0)
@@ -2376,18 +2536,18 @@ def EconomicResults(DirName, CaseName, OptModel, mTEPES, pIndAreaOutput, pIndPlo
2376
2536
  RampUpRev = pd.Series(data=[0.0 for gc in mTEPES.gc], index=mTEPES.gc, dtype='float64')
2377
2537
 
2378
2538
  if mTEPES.pIndRampReserves == 1 and sum(mTEPES.pRampReserveDw[:,:,:,:]):
2379
- if len([(p,sc,n,nr) for p,sc,n,nr in mTEPES.psn*mTEPES.nr if sum(mTEPES.pRampReserveDw[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,nr) in mTEPES.psnnr]):
2380
- sPSSTNNR = [(p,sc,st,n,nr) for p,sc,st,n,nr in mTEPES.s2n*mTEPES.nr if sum(mTEPES.pRampReserveDw[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,nr) in mTEPES.psnnr]
2539
+ if len([(p,sc,n,nr) for p,sc, n,nr in mTEPES.psn*mTEPES.nr if sum(mTEPES.pRampReserveDw[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,nr) in mTEPES.psnnr and (p,nr) in mTEPES.pnr]):
2540
+ sPSSTNNR = [(p,sc,st,n,nr) for p,sc,st,n,nr in mTEPES.s2n*mTEPES.nr if sum(mTEPES.pRampReserveDw[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,nr) in mTEPES.psnnr and (p,nr) in mTEPES.pnr]
2381
2541
  OutputResults = pd.Series(data=[mTEPES.pDuals["".join([f"eSystemRampDw_{p}_{sc}_{st}{n}"])]/mTEPES.pPeriodProb[p,sc]()*OptModel.vRampReserveDw[p,sc,n,nr]() for p,sc,st,n,nr in sPSSTNNR], index=pd.Index(sPSSTNNR))
2382
2542
  OutputResults.to_frame(name='MEUR').reset_index().pivot_table(index=['level_0','level_1','level_3'], columns='level_4', values='MEUR').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).to_csv(f'{_path}/oT_Result_RevenueRampReserveDw_{CaseName}.csv', sep=',')
2383
2543
 
2384
- # if len([(p,sc,n,eh) for p,sc,n,eh in mTEPES.psn*mTEPES.eh if sum(mTEPES.pRampReserveDw[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,eh) in mTEPES.psnehc]):
2385
- # sPSSTNES = [(p,sc,st,n,eh) for p,sc,st,n,eh in mTEPES.s2n*mTEPES.eh if sum(mTEPES.pRampReserveDw[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,eh) in mTEPES.psnehc]
2544
+ # if len([(p,sc,n,eh) for p,sc, n,eh in mTEPES.psn*mTEPES.eh if sum(mTEPES.pRampReserveDw[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,eh) in mTEPES.psnehc and (p,eh) in mTEPES.peh]):
2545
+ # sPSSTNES = [(p,sc,st,n,eh) for p,sc,st,n,eh in mTEPES.s2n*mTEPES.eh if sum(mTEPES.pRampReserveDw[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,eh) in mTEPES.psnehc and (p,eh) in mTEPES.peh]
2386
2546
  # OutputResults = pd.Series(data=[mTEPES.pDuals["".join([f"eSystemRampDw_{p}_{sc}_{st}{n}"])]/mTEPES.pPeriodProb[p,sc]()*OptModel.vRampReserveDw[p,sc,n,eh]() for p,sc,st,n,eh in sPSSTNES], index=pd.Index(sPSSTNES))
2387
2547
  # OutputResults.to_frame(name='MEUR').reset_index().pivot_table(index=['level_0','level_1','level_3'], columns='level_4', values='MEUR').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).to_csv(f'{_path}/oT_Result_RevenueRampReserveDwESS_{CaseName}.csv', sep=',')
2388
2548
 
2389
- if len([(p,sc,n,ec) for p,sc,n,ec in mTEPES.psn*mTEPES.gc if sum(mTEPES.pRampReserveDw[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,ec) in mTEPES.psnec]):
2390
- sPSSTNEC = [(p,sc,st,n,ec) for p,sc,st,n,ec in mTEPES.s2n*mTEPES.ec if sum(mTEPES.pRampReserveDw[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,ec) in mTEPES.psnec]
2549
+ if len([(p,sc,n,ec) for p,sc, n,ec in mTEPES.psn*mTEPES.gc if sum(mTEPES.pRampReserveDw[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,ec) in mTEPES.psnec and (p,ec) in mTEPES.pec]):
2550
+ sPSSTNEC = [(p,sc,st,n,ec) for p,sc,st,n,ec in mTEPES.s2n*mTEPES.ec if sum(mTEPES.pRampReserveDw[p,sc,n,ar] for ar in mTEPES.ar) and (p,sc,n,ec) in mTEPES.psnec and (p,ec) in mTEPES.pec]
2391
2551
  OutputResults = pd.Series(data=[mTEPES.pDuals["".join([f"eSystemRampDw_{p}_{sc}_{st}{n}"])]/mTEPES.pPeriodProb[p,sc]()*OptModel.vRampReserveUp[p,sc,n,ec]() for p,sc,st,n,ec in sPSSTNEC], index=pd.Index(sPSSTNEC), dtype='float64')
2392
2552
  if len(OutputResults):
2393
2553
  OutputToDwRev = OutputResults.to_frame('MEUR').reset_index().pivot_table(index=['level_0','level_1','level_3'], columns='level_4', values='MEUR').rename_axis(['Period', 'Scenario', 'LoadLevel'], axis=0).rename_axis([None], axis=1).sum(axis=0)
@@ -1,5 +1,5 @@
1
1
  """
2
- Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - January 07, 2026
2
+ Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES) - January 21, 2026
3
3
  """
4
4
 
5
5
  import time
@@ -50,8 +50,8 @@ def ProblemSolving(DirName, CaseName, SolverName, OptModel, mTEPES, pIndLogConso
50
50
  # Solver.options['RINSHeur' ] = 100
51
51
  # Solver.options['EpGap' ] = 0.01
52
52
  Solver.options['Threads' ] = int((psutil.cpu_count(logical=True) + psutil.cpu_count(logical=False))/2)
53
- Solver.options['TimeLimit' ] = 36000
54
- # Solver.options['ItLim' ] = 36000000
53
+ Solver.options['TimeLimit' ] = 72000
54
+ # Solver.options['ItLim' ] = 72000000
55
55
  if SolverName == 'appsi_highs':
56
56
  FileName = f'{_path}/openTEPES_highs_{CaseName}_{p}_{sc}_{st}.log'
57
57
  if os.path.exists(FileName):
@@ -63,15 +63,15 @@ def ProblemSolving(DirName, CaseName, SolverName, OptModel, mTEPES, pIndLogConso
63
63
  Solver.options['mip_rel_gap' ] = 0.01
64
64
  Solver.options['parallel' ] = 'on'
65
65
  Solver.options['threads' ] = int((psutil.cpu_count(logical=True) + psutil.cpu_count(logical=False))/2)
66
- Solver.options['time_limit' ] = 36000
67
- Solver.options['simplex_iteration_limit'] = 36000000
66
+ Solver.options['time_limit' ] = 72000
67
+ Solver.options['simplex_iteration_limit'] = 72000000
68
68
  if SolverName == 'gams':
69
69
  FileName = f'{_path}/openTEPES_gams_{CaseName}_{p}_{sc}_{st}.log'
70
70
  solver_options = {
71
71
  'file COPT / cplex.opt / ; put COPT putclose "LPMethod 4" / "EpGap 0.01" / ; GAMS_MODEL.OptFile = 1 ; '
72
72
  'option SysOut = off ;',
73
73
  'option LP = cplex ; option MIP = cplex ;',
74
- 'option ResLim = 36000 ; option IterLim = 36000000 ;',
74
+ 'option ResLim = 72000 ; option IterLim = 72000000 ;',
75
75
  'option Threads = '+str(int((psutil.cpu_count(logical=True) + psutil.cpu_count(logical=False))/2))+' ;'
76
76
  }
77
77
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openTEPES
3
- Version: 4.18.8
3
+ Version: 4.18.9
4
4
  Summary: Open Generation, Storage, and Transmission Operation and Expansion Planning Model with RES and ESS (openTEPES)
5
5
  Home-page: https://opentepes.readthedocs.io/en/latest/index.html
6
6
  Author: IIT-EnergySystemModels
@@ -11,19 +11,19 @@ Classifier: Development Status :: 5 - Production/Stable
11
11
  Classifier: Intended Audience :: Science/Research
12
12
  Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
13
13
  Classifier: Operating System :: OS Independent
14
- Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.13
15
15
  License-File: LICENSE
16
- Requires-Dist: pyomo>=5.7.3
17
- Requires-Dist: matplotlib>=3.3.4
18
- Requires-Dist: numpy>=1.20.1
19
- Requires-Dist: pandas>=1.2.3
20
- Requires-Dist: plotly>=5.7.0
16
+ Requires-Dist: altair>=5.5.0
21
17
  Requires-Dist: colour>=0.1.5
22
- Requires-Dist: altair>=5.0.0
23
- Requires-Dist: psutil>=5.8.0
24
- Requires-Dist: jsonschema>=4.16.0
25
- Requires-Dist: networkx>=3.3
26
18
  Requires-Dist: dill>=0.3.8
19
+ Requires-Dist: duckdb>=1.3.2
20
+ Requires-Dist: jsonschema>=4.26.0
21
+ Requires-Dist: matplotlib>=3.10.0
22
+ Requires-Dist: networkx>=3.6.1
23
+ Requires-Dist: pandas>=2.2.2
24
+ Requires-Dist: plotly>=5.24.1
25
+ Requires-Dist: psutil>=5.9.5
26
+ Requires-Dist: pyomo>=6.9.5
27
27
 
28
28
  .. image:: https://raw.githubusercontent.com/IIT-EnergySystemModels/openTEPES/refs/heads/master/doc/img/openTEPES.png
29
29
  :target: https://opentepes.readthedocs.io/en/latest/index.html
@@ -123,7 +123,7 @@ It determines automatically optimal expansion plans that satisfy simultaneously
123
123
 
124
124
  It represents hierarchically the different time scopes to make decisions in an electric system:
125
125
 
126
- - Load level: one hour, e.g., 01-01 00:00:00+01:00 to 12-30 23:00:00+01:00, or quarter of an hour, e.g., 01-01 00:00:00+01:00 to 30-12 23:45:00+01:00
126
+ - Load level: one hour, e.g., 01-01 00:00:00+01:00 to 12-30 23:00:00+01:00, or **quarter of an hour**, e.g., 01-01 00:00:00+01:00 to 30-12 23:45:00+01:00
127
127
 
128
128
  The time division allows a user-defined flexible representation of the periods for evaluating the system operation. Moreover, it can be run with chronological periods of several consecutive hours (bi-hourly, tri-hourly resolution in case of hourly definition or half an hour in case of quarter of an hour definition) to decrease the computational burden without losing accuracy. The model can be run with a single period (year) or with several periods (years) to allow the analysis of the system's evolution.
129
129
  The time definition also allows for specifying disconnected representative periods (e.g., days, weeks) to evaluate the system operation.
@@ -131,7 +131,7 @@ It determines automatically optimal expansion plans that satisfy simultaneously
131
131
  The period (year) must be represented by 8736 hours because several model concepts representing the system operation are based on weeks (168 hours) or months (made of 4 weeks, 672 hours).
132
132
 
133
133
  - **Stochastic**: several stochastic parameters that can influence the optimal generation, storage, and transmission expansion decisions are considered. The model considers stochastic
134
- medium-term yearly uncertainties (scenarios) related to the system operation. These operation scenarios are associated with renewable energy sources, energy inflows and outflows, natural water inflows, operating reserves, inertia, and electricity, hydrogen, and heat demand.
134
+ medium-term yearly uncertainties (scenarios) related to the system operation. These operation scenarios are associated with renewable energy sources, energy inflows and outflows, natural water inflows, operating reserves, ramp reserves, inertia, and electricity, hydrogen, and heat demand.
135
135
 
136
136
  The objective function incorporates the two main quantifiable costs: **generation, storage, and transmission investment cost (CAPEX)** and **expected variable operation costs (including generation, consumption, emission, and reliability costs) (system OPEX)**.
137
137
 
@@ -150,10 +150,10 @@ Besides, it includes a representation of **Power to Heat (P2H)** by setting the
150
150
  The main results of the model can be structured into these topics:
151
151
 
152
152
  - **Investment**: (generation, storage, hydro reservoirs, electric lines, hydrogen pipelines, and heat pipes) investment decisions and cost
153
- - **Operation**: unit commitment, startup, and shutdown of non-renewable units, unit output and aggregation by technologies (thermal, storage hydro, pumped-hydro storage, RES), RES curtailment, electric line, hydrogen pipeline, and heat pipe flows, line ohmic losses, node voltage angles, upward and downward operating reserves, ESS inventory levels, hydro reservoir volumes, power, hydrogen, and heat not served
153
+ - **Operation**: unit commitment, startup, and shutdown of non-renewable units, unit output and aggregation by technologies (thermal, storage hydro, pumped-hydro storage, RES), RES curtailment, electric line, hydrogen pipeline, and heat pipe flows, line ohmic losses, node voltage angles, upward and downward operating reserves, upward and downward ramp reserves, ESS inventory levels, hydro reservoir volumes, power, hydrogen, and heat not served
154
154
  - **Emissions**: CO2 emissions by unit
155
155
  - **Marginal**: Locational Short-Run Marginal Costs (LSRMC), stored energy value, water volume value
156
- - **Economic**: operation, emission, and reliability costs and revenues from operation and operating reserves
156
+ - **Economic**: operation, emission, and reliability costs and revenues from operation, operating reserves, and ramp reserves
157
157
  - **Flexibility**: flexibility provided by demand, by the different generation and consumption technologies, and by power not served
158
158
 
159
159
  Results are shown in csv files and graphical plots.
@@ -164,7 +164,7 @@ Installation
164
164
  ############
165
165
  `Installation guide <https://pascua.iit.comillas.edu/aramos/openTEPES_installation.pdf>`_.
166
166
 
167
- There are 2 ways to get all the required packages under Windows. We recommend using the Python distribution Miniconda. If you don't want to use it or already have an existing Python (version 3.11) installation, you can also download the required packages by yourself.
167
+ There are 2 ways to get all the required packages under Windows. We recommend using the Python distribution Miniconda. If you don't want to use it or already have an existing Python installation, you can also download the required packages by yourself.
168
168
 
169
169
  Miniconda (recommended)
170
170
  =======================
@@ -1,11 +1,11 @@
1
- openTEPES/__init__.py,sha256=CzNM5Un96U7o_nqkM6CkUFhd8552xJI_a9iFvmGRoFU,832
1
+ openTEPES/__init__.py,sha256=FozTs8PMPcaz1sPtbHKQYWkBTIQar2I6GWwQGq69oXI,832
2
2
  openTEPES/openTEPES.mapbox_token,sha256=xsXNkwGp2vzXqQy2zVkyLhhNcNWniK2BMeOFpc5SZHI,93
3
- openTEPES/openTEPES.py,sha256=RzdXYHSvcja3ujf9wmhm1QvgJU-ChEEJXSz2UDkmVt8,27461
4
- openTEPES/openTEPES_InputData.py,sha256=kAItZuIB6BKWwSxLHcLl_5Te8ZAuZjOnmHCGrwOo7lQ,245623
5
- openTEPES/openTEPES_Main.py,sha256=oq365yAInW7fmsvVeHPRRCU74qtNuTCD4StdAw9tqmk,40782
3
+ openTEPES/openTEPES.py,sha256=CnikcchmCP49DjB81RuAtxz8TEK8MSKMhwV1nEeTbMI,27461
4
+ openTEPES/openTEPES_InputData.py,sha256=ue_B_yaANq5k4w0vo9CPkESWpXfb5BZjF1xFqRpw3to,245619
5
+ openTEPES/openTEPES_Main.py,sha256=glvDODa5hfmSLTXIKamQmt3rlkTFN6d2CMFNMXXuCs0,40782
6
6
  openTEPES/openTEPES_ModelFormulation.py,sha256=g9nRAbJpZ8r1_aIP-EH6t7mJhoWDB8uj8Q8zZjVnwjM,141751
7
- openTEPES/openTEPES_OutputResults.py,sha256=2CapqdOsbCcT-RO2pRjfkgrc5GPjmrUN0IdrZGr6ze0,236028
8
- openTEPES/openTEPES_ProblemSolving.py,sha256=6Q21lf7DqNYV6zaOyyY7IuepxjpapbJ3a-ukObieVM8,16766
7
+ openTEPES/openTEPES_OutputResults.py,sha256=rIcdKqhVyzaizcZiPtN0uGcst1-SHuFF9gs1Fj-zJjM,242215
8
+ openTEPES/openTEPES_ProblemSolving.py,sha256=gORJdW46pSzphOfjIT-vSJ2kgkAEuPWh0exqm7ozx0Q,16766
9
9
  openTEPES/openTEPES_gitinfo.py,sha256=6fA1fa-JcyusSc_HcjPiCgnV9zn-fZwdG-kK0a5Fxc8,2004
10
10
  openTEPES/.idea/.name,sha256=jiwfcnJ20wztcvpny4SHcqmAIWK-w5tCqN9TWf0GOkw,11
11
11
  openTEPES/.idea/misc.xml,sha256=m4-3O284ZBS8WZSQD0QWwk8YjuQYz92w6kr7NRFNips,298
@@ -384,8 +384,8 @@ openTEPES/sSEP/oT_Dict_Storage_sSEP.csv,sha256=H2rJXZvoMuT-25sI2GpG8IuiNKD-dxuty
384
384
  openTEPES/sSEP/oT_Dict_Technology_sSEP.csv,sha256=MCTpplzz7_eVPKQfOw35c86ib6CTtW6UK6JrbCJ8wls,170
385
385
  openTEPES/sSEP/oT_Dict_ZoneToArea_sSEP.csv,sha256=AUDCs5Bg6sw9f2pVjGP1o4IJjXFF_VrokOGf_V3QsEI,24
386
386
  openTEPES/sSEP/oT_Dict_Zone_sSEP.csv,sha256=TBud-fvbFbiAsuutxTYe8wWlv_x1P8oyWXILMpYiXJc,13
387
- opentepes-4.18.8.dist-info/entry_points.txt,sha256=gNNPrDaTsRuRJXI1FLNgqMX1CiJ45bEp1dEDH7ZB8Oc,49
388
- opentepes-4.18.8.dist-info/licenses/LICENSE,sha256=4O7bphXVzRuYavtsWzpLGuM3E-fp3HTRna7F4yIfnS4,35184
389
- opentepes-4.18.8.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
390
- opentepes-4.18.8.dist-info/METADATA,sha256=w_hBKYHhzJX4mz_-_aU8W2cQxVy2N_8UdGg_FrQ3l2Q,19361
391
- opentepes-4.18.8.dist-info/RECORD,,
387
+ opentepes-4.18.9.dist-info/entry_points.txt,sha256=gNNPrDaTsRuRJXI1FLNgqMX1CiJ45bEp1dEDH7ZB8Oc,49
388
+ opentepes-4.18.9.dist-info/licenses/LICENSE,sha256=4O7bphXVzRuYavtsWzpLGuM3E-fp3HTRna7F4yIfnS4,35184
389
+ opentepes-4.18.9.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
390
+ opentepes-4.18.9.dist-info/METADATA,sha256=7bDfXPGg6f_5jya58I6bg6evEtMQx8TDoxr-OaSrbTs,19420
391
+ opentepes-4.18.9.dist-info/RECORD,,