ConniKLu commited on
Commit
41ba494
·
verified ·
1 Parent(s): 33c298f

Upload 4 files

Browse files

update from branch german_light

Files changed (4) hide show
  1. Input_Jahr_2021.xlsx +2 -2
  2. app.py +216 -87
  3. model_data.pkl +2 -2
  4. sourced.py +11 -11
Input_Jahr_2021.xlsx CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:127195ebc8ff48f366fb9a4c0d32a6e4c33a8bba916f4685523f6ef396374f73
3
- size 1126639
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:03bfa05bc9361595ea2345ee1a423193dab5051900e5acc244100ff787c09624
3
+ size 1127885
app.py CHANGED
@@ -32,14 +32,15 @@ col4.header("Download Results")
32
  # Color dictionary for figures
33
  color_dict = {'Biomasse': 'lightgreen',
34
  'Braunkohle': 'red',
35
- 'Erdgas': 'grey',
36
  'Steinkohle': 'darkgrey',
37
  'Erdöl': 'brown',
38
  'Laufwasser': 'aquamarine',
39
- 'Kernenergie': 'orange',
40
  'PV': 'yellow',
41
  'WindOff': 'darkblue',
42
- 'WindOn': 'blue'}
 
43
 
44
  # %%
45
  with col1:
@@ -86,15 +87,14 @@ def timstep_aggregate(time_steps_aggregate, xr ):
86
  t = sets_dict['t']
87
  t_original = sets_dict['t']
88
  i = sets_dict['i']
89
- # iSto = sets_dict['iSto']
90
  iConv = sets_dict['iConv']
91
  # iPtG = sets_dict['iPtG']
92
  iRes = sets_dict['iRes']
93
  # iHyRes = sets_dict['iHyRes']
94
 
95
  # Unpack params_dict into the workspace
96
- # l_co2 = params_dict['l_co2']
97
- l_co2 = 90
98
  p_co2 = params_dict['p_co2']
99
 
100
  eff_i = params_dict['eff_i']
@@ -105,7 +105,7 @@ c_inv_i = params_dict['c_inv_i']
105
  co2_factor_i = params_dict['co2_factor_i']
106
  c_var_i = params_dict['c_var_i']
107
  K_0_i = params_dict['K_0_i']
108
- # e2p_iSto = params_dict['e2p_iSto']
109
 
110
  # Sliders and input boxes for parameters
111
  with col2:
@@ -127,13 +127,12 @@ with col3:
127
  if i_idx in ['Steinkohle', 'Erdöl','Erdgas']:
128
  c_fuel_i.loc[i_idx] = st.slider(value=int(c_fuel_i.loc[i_idx]), min_value=0, max_value=300, label=i_idx + ' Preis [€/MWh]' , step=10)
129
 
130
- technologies_invest = st.multiselect(label='Technologien für Investitionen', options=i, default=['Braunkohle','Erdgas','Steinkohle','Erdöl','PV','WindOff','WindOn','Laufwasser','Kernenergie','Biomasse'])
 
131
  technologies_no_invest = [x for x in i if x not in technologies_invest]
132
 
133
  # Aggregate time series
134
  D_t = timstep_aggregate(dt,params_dict['D_t'])
135
- # D_t sorted descending
136
- D_t_sorted = D_t.sortby(D_t, ascending = False)
137
  s_t_r_iRes = timstep_aggregate(dt,params_dict['s_t_r_iRes'])
138
  # h_t = timstep_aggregate(dt,params_dict['h_t'])
139
  t = D_t.get_index('t')
@@ -164,8 +163,8 @@ C_inv = m.add_variables(name = 'C_inv', lower = 0) # Investment costs
164
 
165
  K = m.add_variables(coords = [i], name = 'K', lower = 0) # Endogenous capacity
166
  y = m.add_variables(coords = [t,i], name = 'y', lower = 0) # Electricity production --> für Elektrolyseure ausschließen
167
- # y_ch = m.add_variables(coords = [t,i], name = 'y_ch', lower = 0) # Electricity consumption --> für alles außer Elektrolyseure und Speicher ausschließen
168
- # l = m.add_variables(coords = [t,i], name = 'l', lower = 0) # Storage filling level
169
  w = m.add_variables(coords = [t], name = 'w', lower = 0)
170
  y_curt = m.add_variables(coords = [t,i], name = 'y_curt', lower = 0) # RES curtailment
171
  # y_h2 = m.add_variables(coords = [t,i], name = 'y_h2', lower = 0)
@@ -183,8 +182,8 @@ C_op_sum = m.add_constraints((y * c_fuel_i/eff_i).sum() * dt == C_op, name = 'C
183
  C_inv_sum = m.add_constraints((K * c_inv_i).sum() == C_inv, name = 'C_inv_sum')
184
 
185
  ## Load serving
186
- # loadserve_t = m.add_constraints((((y ).sum(dims = 'i') - y_ch.sum(dims = 'i')) * dt == D_t.sel(t = t) * dt), name = 'load')
187
- loadserve_t = m.add_constraints((((y ).sum(dims = 'i') ) * dt == D_t.sel(t = t) * dt), name = 'load')
188
 
189
  ## Maximum capacity limit
190
  maxcap_i_t = m.add_constraints((y - K <= K_0_i), name = 'max_cap')
@@ -196,7 +195,7 @@ maxcap_invest_i = m.add_constraints((K.sel(i = technologies_no_invest) <= 0), na
196
  # no_power_prod_iPtG_t = m.add_constraints((y.sel(i = iPtG) <= 0), name = 'prevent_ptg_prod')
197
 
198
  ## Maximum storage charging and discharging
199
- # maxcha_iSto_t = m.add_constraints((y.sel(i = iSto) - y_ch.sel(i = iSto) - K.sel(i = iSto) <= K_0_i.sel(i = iSto)), name = 'max_cha')
200
 
201
  ## Maximum electrolyzer capacity
202
  # ptg_prod_iPtG_t = m.add_constraints((y_ch.sel(i = iPtG) - K.sel(i = iPtG) <= K_0_i.sel(i = iPtG)), name = 'max_cha_ptg')
@@ -208,13 +207,13 @@ maxcap_invest_i = m.add_constraints((K.sel(i = technologies_no_invest) <= 0), na
208
  infeed_iRes_t = m.add_constraints((y.sel(i = iRes) - s_t_r_iRes.sel(i = iRes).sel(t = t) * K.sel(i = iRes) + y_curt.sel(i = iRes) == s_t_r_iRes.sel(i = iRes).sel(t = t) * K_0_i.sel(i = iRes)), name = 'infeed')
209
 
210
  ## Maximum filling level restriction storage power plant
211
- # maxcapsto_iSto_t = m.add_constraints((l.sel(i = iSto) - K.sel(i = iSto) * e2p_iSto.sel(i = iSto) <= K_0_i.sel(i = iSto) * e2p_iSto.sel(i = iSto)), name = 'max_sto_filling')
212
 
213
  ## Filling level restriction hydro reservoir
214
  # filling_iHydro_t = m.add_constraints(l.sel(i = iHyRes) - l.sel(i = iHyRes).roll(t = -1) + y.sel(i = iHyRes) * dt == h_t.sel(t = t) * dt, name = 'filling_level_hydro')
215
 
216
  ## Filling level restriction other storages
217
- # filling_iSto_t = m.add_constraints(l.sel(i = iSto) - (l.sel(i = iSto).roll(t = -1) + (y.sel(i = iSto) / eff_i.sel(i = iSto)) * dt - y_ch.sel(i = iSto) * eff_i.sel(i = iSto) * dt) == 0, name = 'filling_level')
218
 
219
  ## CO2 limit
220
  CO2_limit = m.add_constraints(((y / eff_i) * co2_factor_i * dt).sum() <= l_co2 * 1_000_000 , name = 'CO2_limit')
@@ -222,7 +221,8 @@ CO2_limit = m.add_constraints(((y / eff_i) * co2_factor_i * dt).sum() <= l_co2 *
222
  ## set run-of-river power plants capacity limit to 5 GW
223
  RoR_cap = m.add_constraints(K.sel(i = 'Laufwasser') <= 5000, name = 'RoR_cap')
224
  Biomass_cap = m.add_constraints(K.sel(i = 'Biomasse') <= 9000, name = 'Biomass_cap')
225
-
 
226
 
227
  # %%
228
  m.solve(solver_name = 'highs')
@@ -268,25 +268,46 @@ with colb1:
268
  fig
269
 
270
  # %%
271
- #add pie chart which shows new capacities
272
- #round number of new capacities
273
- df_new_capacities_rounded = m.solution['K'].round(0).to_dataframe()
274
- #drop all technologies with K<= 0
275
- df_new_capacities_rounded = df_new_capacities_rounded[df_new_capacities_rounded["K"] > 0].reset_index()
276
-
277
- total_k_sum = df_new_capacities_rounded["K"].sum()
278
-
279
- #df_new_capacities_rounded["percentage"] = df_new_capacities_rounded["K"].apply(lambda x: (x/total_k_sum)*100).abs().round(2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
280
 
281
- fig = px.pie(df_new_capacities_rounded, names='i', values='K', title='Neu installierte Kapazitäten [MW] als Kuchendiagramm',
282
- color='i', color_discrete_map=color_dict)
283
-
284
- with colb1:
285
  fig
286
 
287
-
288
-
289
-
290
  # %%
291
  i_with_capacity = m.solution['K'].where( m.solution['K'] > 0).dropna(dim = 'i').get_index('i')
292
  df_production = m.solution['y'].sel(i = i_with_capacity).to_dataframe().reset_index()
@@ -294,44 +315,48 @@ fig = px.area(m.solution['y'].sel(i = i_with_capacity).to_dataframe().reset_inde
294
  fig.update_traces(line=dict(width=0))
295
  fig.for_each_trace(lambda trace: trace.update(fillcolor = trace.line.color))
296
 
297
- with colb2:
298
  fig
299
- # %%
300
- #Add pie chart of total production per technology type in GWh(divide by 1000)
301
- df_production_sum = (df_production.groupby('i')['y'].sum() * dt / 1000 ).round(0).sort_values(ascending=False).reset_index()
302
 
303
- fig = px.pie(df_production_sum, names="i", values='y', title='Gesamtproduktion [GWh] als Kuchendiagramm',
304
- color='i', color_discrete_map=color_dict)
305
-
306
- with colb2:
307
- fig
308
 
309
  # %%
310
-
311
  df_price = m.constraints['load'].dual.to_dataframe().reset_index()
 
 
 
 
 
 
312
 
313
- fig = px.line(df_price, y='dual', x='t', title='Strompreis [€/MWh]', range_y=[0,350])
314
- with colb1:
315
  fig
316
 
317
-
318
  # %%
319
- # df_sorted_price = df_price["dual"].repeat(dt).sort_values(ascending=False).reset_index(drop=True)/int(dt)
320
- df_sorted_price = df_price["dual"].sort_values(ascending=False).reset_index(drop=True)
321
-
322
- fig = px.line(y=df_sorted_price, x=df_sorted_price.index, title='Preisdauerlinie [€/MWh]', labels={"x": "Stunden im Jahr"},range_y=[0,350])
 
 
 
 
 
 
 
 
 
 
 
 
323
  with colb1:
324
  fig
325
-
326
- # %%
327
-
328
- df_contr_marg = m.constraints['max_cap'].dual.to_dataframe().reset_index()
329
- df_contr_marg['dual'] = df_contr_marg['dual'] / dt * (-1)
330
-
331
 
332
  # %%
333
 
334
- fig = px.line(df_contr_marg, y='dual', x='t',title='Deckungsbeitrag []', color='i', range_y=[0,350], color_discrete_map=color_dict)
335
  with colb2:
336
  fig
337
 
@@ -346,62 +371,147 @@ fig.for_each_trace(lambda trace: trace.update(fillcolor = trace.line.color))
346
  with colb1:
347
  fig
348
 
 
349
  # %%
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
350
  df_production_pivot = df_production.pivot(index='t', columns='i', values='y')
351
  # sort columns according to i_with_capacity
352
  df_production_pivot = df_production_pivot[i_with_capacity]
 
353
  co2_factor_i_with_capacity = co2_factor_i.sel(i = i_with_capacity)
354
  # colour_dict = {i: color_dict[i] for i in i_with_capacity}
355
  color_dict_with_capacity = {i: color_dict[i] for i in i_with_capacity}
356
-
357
  # multiply df_production with co2 factor
358
- df_production_emissions = df_production_pivot * co2_factor_i_with_capacity
359
  # unpivot df_production_emissions, sorting by datetime
360
  df_production_emissions_unpivot = df_production_emissions.reset_index().melt(id_vars='t', var_name='i', value_name='y')
361
- df_production_emissions_unpivot = df_production_emissions_unpivot.sort_values(by='t')
362
- # sum up y column in total
363
- df_production_emissions_total = df_production_emissions_unpivot['y'].sum()
364
- df_production_emissions_sorted = df_production_emissions_unpivot.sort_values(by='y', ascending=True)
365
- # sum up cumulated emissions
366
- df_production_emissions_sorted['cumsum'] = df_production_emissions_sorted['y'].cumsum()
367
 
368
  # generate area plot of df_production_emissions_unpivot over t
369
  fig = px.area(df_production_emissions_unpivot, y='y', x='t', title='Co2-Emissionen [t]', color='i', color_discrete_map=color_dict_with_capacity)
370
  fig.update_traces(line=dict(width=0))
371
  fig.for_each_trace(lambda trace: trace.update(fillcolor = trace.line.color))
372
- # fig = px.area(df_production_emissions_unpivot.sel(i = i_with_capacity).to_dataframe().reset_index(), y='y', x='t', title='Stromproduktion Lastgang [MW]', color='i', color_discrete_map=color_dict)
373
- # fig.update_traces(line=dict(width=0))
374
- # fig.for_each_trace(lambda trace: trace.update(fillcolor = trace.line.color))
375
- with colb2:
376
- fig
377
 
 
 
378
 
379
  # %%
380
- # generate area plot of df_production_emissions_sorted['cumsum] over t
381
- x_emissions = np.arange(1, df_production_emissions_sorted['t'].size + 1)
382
- fig = px.area(df_production_emissions_sorted, y='cumsum', x=x_emissions, title='Kumulierte Co2-Emissionen [t]', color='i', color_discrete_map=color_dict_with_capacity)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
383
  fig.update_traces(line=dict(width=0))
384
- fig.for_each_trace(lambda trace: trace.update(fillcolor = trace.line.color))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
385
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386
  with colb2:
387
  fig
388
 
389
  # %%
390
- # df_charging = m.solution['y_ch'].sel(i = iSto).to_dataframe().reset_index()
391
- # fig = px.area(m.solution['y_ch'].sel(i = iSto).to_dataframe().reset_index(), y='y_ch', x='t', title='Speicherbeladung [MWh]', color='i', color_discrete_map=color_dict)
392
- # fig.update_traces(line=dict(width=0))
393
- # fig.for_each_trace(lambda trace: trace.update(fillcolor = trace.line.color))
 
394
 
395
  # with colb2:
396
  # fig
397
 
398
  # %%
399
- # define vector x with size (1,size D_t_sorted)
400
- x = np.arange(1, D_t_sorted.size + 1)
401
- fig = px.line(y=D_t_sorted, x=x, title='Lastdauerlinie [€/MWh]', labels={"x": "Stunden im Jahr"})
402
- with colb2:
403
- fig
404
-
405
  # # %%
406
  # df_h2_prod = m.solution['y_h2'].sel(i = iPtG).to_dataframe().reset_index()
407
  # fig = px.area(m.solution['y_h2'].sel(i = iPtG).to_dataframe().reset_index(), y='y_h2', x='t', title='Produktion Wasserstoff [MWh_th]', color='i', color_discrete_map=color_dict)
@@ -411,6 +521,25 @@ with colb2:
411
  # with colb2:
412
  # fig
413
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
414
  # %%
415
  ((m.solution['y'] / eff_i) * co2_factor_i * dt).sum()
416
  # %%
@@ -453,10 +582,10 @@ with pd.ExcelWriter(output, engine='xlsxwriter') as writer:
453
  disaggregate_df(df_total_costs).to_excel(writer, sheet_name='Gesamtkosten', index=False)
454
  disaggregate_df(df_CO2_price).to_excel(writer, sheet_name='CO2 Preis', index=False)
455
  disaggregate_df(df_price).to_excel(writer, sheet_name='Preise', index=False)
456
- disaggregate_df(df_contr_marg).to_excel(writer, sheet_name='Deckungsbeiträge', index=False)
457
  disaggregate_df(df_new_capacities).to_excel(writer, sheet_name='Kapazitäten', index=False)
458
  disaggregate_df(df_production).to_excel(writer, sheet_name='Produktion', index=False)
459
- # disaggregate_df(df_charging).to_excel(writer, sheet_name='Ladevorgänge', index=False)
460
  disaggregate_df(D_t.to_dataframe().reset_index()).to_excel(writer, sheet_name='Nachfrage', index=False)
461
  disaggregate_df(df_curtailment).to_excel(writer, sheet_name='Abregelung', index=False)
462
  # disaggregate_df(df_h2_prod).to_excel(writer, sheet_name='H2 produktion', index=False)
 
32
  # Color dictionary for figures
33
  color_dict = {'Biomasse': 'lightgreen',
34
  'Braunkohle': 'red',
35
+ 'Erdgas': 'orange',
36
  'Steinkohle': 'darkgrey',
37
  'Erdöl': 'brown',
38
  'Laufwasser': 'aquamarine',
39
+ 'Kernenergie': 'cyan',
40
  'PV': 'yellow',
41
  'WindOff': 'darkblue',
42
+ 'WindOn': 'blue',
43
+ 'Batteriespeicher': 'purple'}
44
 
45
  # %%
46
  with col1:
 
87
  t = sets_dict['t']
88
  t_original = sets_dict['t']
89
  i = sets_dict['i']
90
+ iSto = sets_dict['iSto']
91
  iConv = sets_dict['iConv']
92
  # iPtG = sets_dict['iPtG']
93
  iRes = sets_dict['iRes']
94
  # iHyRes = sets_dict['iHyRes']
95
 
96
  # Unpack params_dict into the workspace
97
+ l_co2 = params_dict['l_co2']
 
98
  p_co2 = params_dict['p_co2']
99
 
100
  eff_i = params_dict['eff_i']
 
105
  co2_factor_i = params_dict['co2_factor_i']
106
  c_var_i = params_dict['c_var_i']
107
  K_0_i = params_dict['K_0_i']
108
+ e2p_iSto = params_dict['e2p_iSto']
109
 
110
  # Sliders and input boxes for parameters
111
  with col2:
 
127
  if i_idx in ['Steinkohle', 'Erdöl','Erdgas']:
128
  c_fuel_i.loc[i_idx] = st.slider(value=int(c_fuel_i.loc[i_idx]), min_value=0, max_value=300, label=i_idx + ' Preis [€/MWh]' , step=10)
129
 
130
+ # technologies_invest = st.multiselect(label='Technologien für Investitionen', options=i, default=['Biomasse','Laufwasser','Kernenergie','Braunkohle','Steinkohle','Erdöl','Erdgas','WindOff','WindOn','PV','Batteriespeicher'])
131
+ technologies_invest = st.multiselect(label='Technologien für Investitionen', options=i, default=['Kernenergie','Braunkohle','Steinkohle','Erdgas'])
132
  technologies_no_invest = [x for x in i if x not in technologies_invest]
133
 
134
  # Aggregate time series
135
  D_t = timstep_aggregate(dt,params_dict['D_t'])
 
 
136
  s_t_r_iRes = timstep_aggregate(dt,params_dict['s_t_r_iRes'])
137
  # h_t = timstep_aggregate(dt,params_dict['h_t'])
138
  t = D_t.get_index('t')
 
163
 
164
  K = m.add_variables(coords = [i], name = 'K', lower = 0) # Endogenous capacity
165
  y = m.add_variables(coords = [t,i], name = 'y', lower = 0) # Electricity production --> für Elektrolyseure ausschließen
166
+ y_ch = m.add_variables(coords = [t,i], name = 'y_ch', lower = 0) # Electricity consumption --> für alles außer Elektrolyseure und Speicher ausschließen
167
+ l = m.add_variables(coords = [t,i], name = 'l', lower = 0) # Storage filling level
168
  w = m.add_variables(coords = [t], name = 'w', lower = 0)
169
  y_curt = m.add_variables(coords = [t,i], name = 'y_curt', lower = 0) # RES curtailment
170
  # y_h2 = m.add_variables(coords = [t,i], name = 'y_h2', lower = 0)
 
182
  C_inv_sum = m.add_constraints((K * c_inv_i).sum() == C_inv, name = 'C_inv_sum')
183
 
184
  ## Load serving
185
+ loadserve_t = m.add_constraints((((y ).sum(dims = 'i') - y_ch.sum(dims = 'i')) * dt == D_t.sel(t = t) * dt), name = 'load')
186
+ # loadserve_t = m.add_constraints((((y ).sum(dims = 'i') ) * dt == D_t.sel(t = t) * dt), name = 'load')
187
 
188
  ## Maximum capacity limit
189
  maxcap_i_t = m.add_constraints((y - K <= K_0_i), name = 'max_cap')
 
195
  # no_power_prod_iPtG_t = m.add_constraints((y.sel(i = iPtG) <= 0), name = 'prevent_ptg_prod')
196
 
197
  ## Maximum storage charging and discharging
198
+ maxcha_iSto_t = m.add_constraints((y.sel(i = iSto) - y_ch.sel(i = iSto) - K.sel(i = iSto) <= K_0_i.sel(i = iSto)), name = 'max_cha')
199
 
200
  ## Maximum electrolyzer capacity
201
  # ptg_prod_iPtG_t = m.add_constraints((y_ch.sel(i = iPtG) - K.sel(i = iPtG) <= K_0_i.sel(i = iPtG)), name = 'max_cha_ptg')
 
207
  infeed_iRes_t = m.add_constraints((y.sel(i = iRes) - s_t_r_iRes.sel(i = iRes).sel(t = t) * K.sel(i = iRes) + y_curt.sel(i = iRes) == s_t_r_iRes.sel(i = iRes).sel(t = t) * K_0_i.sel(i = iRes)), name = 'infeed')
208
 
209
  ## Maximum filling level restriction storage power plant
210
+ maxcapsto_iSto_t = m.add_constraints((l.sel(i = iSto) - K.sel(i = iSto) * e2p_iSto.sel(i = iSto) <= K_0_i.sel(i = iSto) * e2p_iSto.sel(i = iSto)), name = 'max_sto_filling')
211
 
212
  ## Filling level restriction hydro reservoir
213
  # filling_iHydro_t = m.add_constraints(l.sel(i = iHyRes) - l.sel(i = iHyRes).roll(t = -1) + y.sel(i = iHyRes) * dt == h_t.sel(t = t) * dt, name = 'filling_level_hydro')
214
 
215
  ## Filling level restriction other storages
216
+ filling_iSto_t = m.add_constraints(l.sel(i = iSto) - (l.sel(i = iSto).roll(t = -1) + (y.sel(i = iSto) / eff_i.sel(i = iSto)) * dt - y_ch.sel(i = iSto) * eff_i.sel(i = iSto) * dt) == 0, name = 'filling_level')
217
 
218
  ## CO2 limit
219
  CO2_limit = m.add_constraints(((y / eff_i) * co2_factor_i * dt).sum() <= l_co2 * 1_000_000 , name = 'CO2_limit')
 
221
  ## set run-of-river power plants capacity limit to 5 GW
222
  RoR_cap = m.add_constraints(K.sel(i = 'Laufwasser') <= 5000, name = 'RoR_cap')
223
  Biomass_cap = m.add_constraints(K.sel(i = 'Biomasse') <= 9000, name = 'Biomass_cap')
224
+ # Nuclear_cap = m.add_constraints(K.sel(i = 'Kernenergie') <= 3000, name = 'Kernenergie_cap')
225
+ # nuclear_production_constraint = m.add_constraints(y.sel(i='Kernenergie') == K.sel(i='Kernenergie'), name='Nuclear_Production_Capacity')
226
 
227
  # %%
228
  m.solve(solver_name = 'highs')
 
268
  fig
269
 
270
  # %%
271
+ D_t_sorted = D_t.sortby(D_t, ascending = False).to_dataframe().reset_index()
272
+ # NaN entries to the end
273
+ D_t_sorted = D_t_sorted.sort_values(by='Nachfrage', ascending=False).reset_index(drop=True)
274
+ # expand df_price to the size of t
275
+ D_t_sorted = D_t_sorted.loc[D_t_sorted.index.repeat(dt)].reset_index(drop=True)
276
+ x_loadcurve = np.arange(1, D_t_sorted['Nachfrage'].size + 1)
277
+
278
+ # residual load curve
279
+ df_production_res = m.solution['y'].sel(i = iRes).to_dataframe().reset_index()
280
+ # sum up over t
281
+ df_production_res_sum = df_production_res.groupby('t')['y'].sum().reset_index()
282
+ # D_t into dateframe
283
+ D_t_df = D_t.to_dataframe().reset_index()
284
+ df_residual = D_t_df['Nachfrage'] - df_production_res_sum['y']
285
+ # sort
286
+ df_residual = df_residual.sort_values(ascending=False).reset_index(drop=True)
287
+ df_residual = df_residual.loc[df_residual.index.repeat(dt)].reset_index(drop=True)
288
+
289
+ df_combined = pd.DataFrame({
290
+ 'x': np.concatenate([x_loadcurve, x_loadcurve]),
291
+ 'y': np.concatenate([D_t_sorted['Nachfrage'], df_residual]),
292
+ 'label': ['Nachfrage'] * len(x_loadcurve) + ['Residual Load'] * len(x_loadcurve)
293
+ })
294
+
295
+ # Create the integrated plot using Plotly Express
296
+ fig = px.line(df_combined, x='x', y='y', color='label', title='Lastdauerlinie [€/MW]',
297
+ labels={"x": "Stunden im Jahr", "y": "Leistung [MW]"})
298
+
299
+ # Specific updates for each trace
300
+ fig.for_each_trace(
301
+ lambda trace: trace.update(line=dict(color='blue')) if trace.name == 'Nachfrage' else trace.update(line=dict(color='red', dash='dash'))
302
+ )
303
 
304
+ with colb2:
305
+ fig.update_layout(
306
+ legend_title='Legende'
307
+ )
308
  fig
309
 
310
+ # fig.show()
 
 
311
  # %%
312
  i_with_capacity = m.solution['K'].where( m.solution['K'] > 0).dropna(dim = 'i').get_index('i')
313
  df_production = m.solution['y'].sel(i = i_with_capacity).to_dataframe().reset_index()
 
315
  fig.update_traces(line=dict(width=0))
316
  fig.for_each_trace(lambda trace: trace.update(fillcolor = trace.line.color))
317
 
318
+ with colb1:
319
  fig
320
+ # fig.show()
 
 
321
 
 
 
 
 
 
322
 
323
  # %%
 
324
  df_price = m.constraints['load'].dual.to_dataframe().reset_index()
325
+ # expand df_price to the size of t
326
+ df_price = df_price.loc[df_price.index.repeat(dt)].reset_index(drop=True)
327
+ # sort prices descending
328
+ df_sorted_price = df_price["dual"].sort_values(ascending=False).reset_index(drop=True)
329
+ # generate x-axis for price duration curve
330
+ x_price = np.arange(1, df_sorted_price.size + 1)
331
 
332
+ fig = px.line(y=df_sorted_price, x=x_price, title='Preisdauerlinie [€/MWh]', labels={"x": "Stunden im Jahr"},range_y=[0,350])
333
+ with colb2:
334
  fig
335
 
 
336
  # %%
337
+ # calculate full load hours
338
+ df_capacity = m.solution['K'].sel(i = i_with_capacity).to_dataframe().reset_index()
339
+ df_production_sum = (df_production.groupby('i')['y'].sum() * dt).round(0).reset_index()
340
+ # reorder rows according to i_with_capacity
341
+ df_production_sum = df_production_sum.set_index('i').loc[i_with_capacity].reset_index()
342
+ # df_production_sum['i'] = pd.Categorical(df_production_sum['i'], categories=desired_order, ordered=True)
343
+
344
+ df_fullload = df_production_sum['y']/df_capacity['K']
345
+ # to dataframe
346
+ df_fullload = df_fullload.to_frame()
347
+ # rename column
348
+ df_fullload.columns = ['fullload']
349
+ df_fullload['i'] = df_production_sum['i']
350
+ # change order of columns
351
+ df_fullload = df_fullload[['i', 'fullload']]
352
+ fig = px.bar(df_fullload, y='i', x=df_fullload['fullload'], orientation='h', title='Volllaststunden [h]', color='i', color_discrete_map=color_dict)
353
  with colb1:
354
  fig
355
+ # fig.show()
 
 
 
 
 
356
 
357
  # %%
358
 
359
+ fig = px.line(df_price, y='dual', x='t', title='Strompreis [€/MWh]', range_y=[0,350])
360
  with colb2:
361
  fig
362
 
 
371
  with colb1:
372
  fig
373
 
374
+
375
  # %%
376
+ df_charging = m.solution['y_ch'].sel(i = iSto).to_dataframe().reset_index()
377
+ fig = px.area(m.solution['y_ch'].sel(i = iSto).to_dataframe().reset_index(), y='y_ch', x='t', title='Speicherbeladung [MWh]', color='i', color_discrete_map=color_dict)
378
+ fig.update_traces(line=dict(width=0))
379
+ fig.for_each_trace(lambda trace: trace.update(fillcolor = trace.line.color))
380
+
381
+ with colb2:
382
+ fig
383
+
384
+ # %%
385
+
386
+ # df_contr_marg = m.constraints['max_cap'].dual.to_dataframe().reset_index()
387
+ # df_contr_marg['dual'] = df_contr_marg['dual'] / dt * (-1)
388
+
389
+ # fig = px.line(df_contr_marg, y='dual', x='t',title='Deckungsbeitrag [€]', color='i', range_y=[0,350], color_discrete_map=color_dict)
390
+ # with colb2:
391
+ # fig
392
+
393
+ # %%
394
+ # generate dataframe steplength = 1 same size as t
395
+ # x = np.arange(1, t.size + 1)
396
+ x = np.arange(1,t.size)
397
  df_production_pivot = df_production.pivot(index='t', columns='i', values='y')
398
  # sort columns according to i_with_capacity
399
  df_production_pivot = df_production_pivot[i_with_capacity]
400
+ df_efficiency = eff_i.sel(i = i_with_capacity)
401
  co2_factor_i_with_capacity = co2_factor_i.sel(i = i_with_capacity)
402
  # colour_dict = {i: color_dict[i] for i in i_with_capacity}
403
  color_dict_with_capacity = {i: color_dict[i] for i in i_with_capacity}
404
+ desired_order = i_with_capacity.tolist()
405
  # multiply df_production with co2 factor
406
+ df_production_emissions = df_production_pivot/df_efficiency * co2_factor_i_with_capacity*dt
407
  # unpivot df_production_emissions, sorting by datetime
408
  df_production_emissions_unpivot = df_production_emissions.reset_index().melt(id_vars='t', var_name='i', value_name='y')
409
+ df_production_emissions_unpivot['i'] = pd.Categorical(df_production_emissions_unpivot['i'], categories=desired_order, ordered=True)
410
+ df_production_emissions_unpivot = df_production_emissions_unpivot.sort_values(by=['t', 'i'])
411
+ # rearrange rows according to i_with_capacity
412
+
 
 
413
 
414
  # generate area plot of df_production_emissions_unpivot over t
415
  fig = px.area(df_production_emissions_unpivot, y='y', x='t', title='Co2-Emissionen [t]', color='i', color_discrete_map=color_dict_with_capacity)
416
  fig.update_traces(line=dict(width=0))
417
  fig.for_each_trace(lambda trace: trace.update(fillcolor = trace.line.color))
 
 
 
 
 
418
 
419
+ with colb1:
420
+ fig
421
 
422
  # %%
423
+ # Sum up second row of df_production_emissions
424
+ df_production_emissions_sum = df_production_emissions.copy()
425
+ df_production_emissions_sum['total'] = df_production_emissions_sum.sum(axis=1)
426
+ # sort by total generation
427
+ df_production_emissions_sum = df_production_emissions_sum.sort_values(by='total', ascending=True)
428
+ # add cumcum column
429
+ df_production_emissions_sum['cumsum'] = df_production_emissions_sum['total'].cumsum()
430
+ # make t an ordinary column
431
+ df_production_emissions_sum = df_production_emissions_sum.reset_index()
432
+ # add index column
433
+ df_production_emissions_sum['num'] = np.arange(1, df_production_emissions_sum['total'].size + 1)
434
+
435
+ # unpivot df_production_emissions_sum
436
+ unpivoted_df = df_production_emissions_sum.melt(id_vars=['t', 'num'], var_name='i', value_name='y')
437
+ # sort by num
438
+ unpivoted_df_sorted = unpivoted_df.sort_values(by='num', ascending=True)
439
+ # extract those rows where i is in i_with_capacity
440
+ unpivoted_df_sorted_cap = unpivoted_df_sorted[unpivoted_df_sorted['i'].isin(i_with_capacity)]
441
+ # generate stacked area plot of df_unpivoted with i = i_with_capacity
442
+ fig = px.area(unpivoted_df_sorted_cap, y='y', x='t', title='Kumulierte Co2-Emissionen [t]', color='i', color_discrete_map=color_dict_with_capacity)
443
+
444
+ # Update traces
445
  fig.update_traces(line=dict(width=0))
446
+ fig.for_each_trace(lambda trace: trace.update(fillcolor=trace.line.color))
447
+
448
+ # fig.show()
449
+ with colb2:
450
+ fig
451
+
452
+
453
+ # %%
454
+ # plot investment costs
455
+ # c-inv_i to dataframe
456
+ if c_inv_i.name is None:
457
+ c_inv_i.name = 'c_inv_i'
458
+ c_inv_i_df = c_inv_i.to_dataframe().reset_index()
459
+ # multiply c_inv_i_df with K
460
+ df_invest_costs = df_new_capacities['K']* c_inv_i
461
+ df_invest_costs = df_invest_costs.to_frame()
462
+ df_invest_costs.columns = ['K']
463
+ df_invest_costs['i'] = df_new_capacities['i']
464
+ fig = px.bar(df_invest_costs, y='i', x='K', orientation='h', title='Investitionskosten [Mrd. €]', color='i', color_discrete_map=color_dict)
465
+ # fig.show()
466
+ with colb1:
467
+ fig
468
+
469
 
470
+ # %%
471
+ df_production_all = m.solution['y'].sel(i = i).to_dataframe().reset_index()
472
+ # Deckungsbeitrag = Erlöse - Kosten
473
+ df_contr_marg = m.constraints['max_cap'].dual.to_dataframe().reset_index()
474
+ # # contr_margin for i_with_capacity
475
+ # df_contr_marg = df_contr_marg[df_contr_marg['i'].isin(i_with_capacity)]. reset_index(drop=True)
476
+ # # multiply
477
+ df_merged = pd.merge(df_production_all, df_contr_marg, on=['t', 'i'])
478
+ # Perform the multiplication
479
+ df_merged['y_new'] = df_merged['y'] * df_merged['dual']
480
+ df_merged = df_merged[['t', 'i', 'y_new']]
481
+ df_contr_marg_sum = df_merged.groupby('i')['y_new'].sum().reset_index()
482
+
483
+ df_production_res = m.solution['y'].sel(i = iRes).to_dataframe().reset_index()
484
+ df_price_res = m.constraints['load'].dual.to_dataframe().reset_index()
485
+ # multiply with df_price_res
486
+ df_merged_res = pd.merge(df_production_res, df_price_res, on='t')
487
+ df_merged_res['multiplied_value'] = df_merged_res['y'] * df_merged_res['dual']
488
+ df_merged_res = df_merged_res[['t', 'i', 'multiplied_value']]
489
+ df_contr_marg_res = df_merged_res.groupby('i')['multiplied_value'].sum().reset_index()
490
+ df_contr_marg_res['multiplied_value'] = df_contr_marg_res['multiplied_value'] * -dt
491
+
492
+ df_contr_marg_sum = pd.merge(df_contr_marg_sum, df_contr_marg_res, on='i', how='left')
493
+ df_contr_marg_sum['y_new'] = df_contr_marg_sum['multiplied_value'].combine_first(df_contr_marg_sum['y_new'])
494
+ df_contr_marg_sum = df_contr_marg_sum.drop(columns=['multiplied_value'])
495
+ df_contr_marg_sum['y'] = df_contr_marg_sum['y_new']*(-1)
496
+ # rearrange rows according to i
497
+ df_contr_marg_sum = df_contr_marg_sum.set_index('i').loc[i].reset_index()
498
+ # # # barplot
499
+ fig = px.bar(df_contr_marg_sum, y='i', x='y', orientation='h', title='Deckungsbeitrag [Mrd. €]', color='i', color_discrete_map=color_dict)
500
+ # fig.show()
501
  with colb2:
502
  fig
503
 
504
  # %%
505
+ # #Add pie chart of total production per technology type in GWh(divide by 1000)
506
+ # df_production_sum = (df_production.groupby('i')['y'].sum() * dt / 1000 ).round(0).sort_values(ascending=False).reset_index()
507
+
508
+ # fig = px.pie(df_production_sum, names="i", values='y', title='Gesamtproduktion [GWh] als Kuchendiagramm',
509
+ # color='i', color_discrete_map=color_dict)
510
 
511
  # with colb2:
512
  # fig
513
 
514
  # %%
 
 
 
 
 
 
515
  # # %%
516
  # df_h2_prod = m.solution['y_h2'].sel(i = iPtG).to_dataframe().reset_index()
517
  # fig = px.area(m.solution['y_h2'].sel(i = iPtG).to_dataframe().reset_index(), y='y_h2', x='t', title='Produktion Wasserstoff [MWh_th]', color='i', color_discrete_map=color_dict)
 
521
  # with colb2:
522
  # fig
523
 
524
+
525
+ # %%
526
+ # #add pie chart which shows new capacities
527
+ # #round number of new capacities
528
+ # df_new_capacities_rounded = m.solution['K'].round(0).to_dataframe()
529
+ # #drop all technologies with K<= 0
530
+ # df_new_capacities_rounded = df_new_capacities_rounded[df_new_capacities_rounded["K"] > 0].reset_index()
531
+
532
+ # total_k_sum = df_new_capacities_rounded["K"].sum()
533
+
534
+ # #df_new_capacities_rounded["percentage"] = df_new_capacities_rounded["K"].apply(lambda x: (x/total_k_sum)*100).abs().round(2)
535
+
536
+ # fig = px.pie(df_new_capacities_rounded, names='i', values='K', title='Neu installierte Kapazitäten [MW] als Kuchendiagramm',
537
+ # color='i', color_discrete_map=color_dict)
538
+
539
+ # with colb1:
540
+ # fig
541
+
542
+
543
  # %%
544
  ((m.solution['y'] / eff_i) * co2_factor_i * dt).sum()
545
  # %%
 
582
  disaggregate_df(df_total_costs).to_excel(writer, sheet_name='Gesamtkosten', index=False)
583
  disaggregate_df(df_CO2_price).to_excel(writer, sheet_name='CO2 Preis', index=False)
584
  disaggregate_df(df_price).to_excel(writer, sheet_name='Preise', index=False)
585
+ # disaggregate_df(df_contr_marg).to_excel(writer, sheet_name='Deckungsbeiträge', index=False)
586
  disaggregate_df(df_new_capacities).to_excel(writer, sheet_name='Kapazitäten', index=False)
587
  disaggregate_df(df_production).to_excel(writer, sheet_name='Produktion', index=False)
588
+ disaggregate_df(df_charging).to_excel(writer, sheet_name='Ladevorgänge', index=False)
589
  disaggregate_df(D_t.to_dataframe().reset_index()).to_excel(writer, sheet_name='Nachfrage', index=False)
590
  disaggregate_df(df_curtailment).to_excel(writer, sheet_name='Abregelung', index=False)
591
  # disaggregate_df(df_h2_prod).to_excel(writer, sheet_name='H2 produktion', index=False)
model_data.pkl CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:3454912d7cfa9b850e8d7651b73c143a7e177d02261d6671a9a8e2d3bc6b81cc
3
- size 1065854
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:38a1f162728d5c9435fe52ad066ab037ba90d3c41122d003b7dc754973ea00c1
3
+ size 1066427
sourced.py CHANGED
@@ -39,8 +39,8 @@ def load_data_from_excel(url_excel, write_to_pickle_flag = True):
39
  df_excel = pd.read_excel(url_excel, sheet_name='Technologies')
40
  iRes = pd.Index(df_excel.iloc[0:4, 4], name='iRes')
41
 
42
- # df_excel = pd.read_excel(url_excel, sheet_name='Technologies')
43
- # iSto = pd.Index(df_excel.iloc[0:2, 6], name='iSto')
44
 
45
  # df_excel = pd.read_excel(url_excel, sheet_name='Technologies')
46
  # iPtG = pd.Index(df_excel.iloc[0:1, 8], name='iPtG')
@@ -145,13 +145,13 @@ def load_data_from_excel(url_excel, write_to_pickle_flag = True):
145
  df_excel = df_excel.set_index('i')
146
  K_0_i = df_excel.iloc[:,0].to_xarray()
147
 
148
- # # Energy-to-power ratio storages
149
- # df_excel = pd.read_excel(url_excel, sheet_name = 'E2P')
150
- # df_excel = df_excel.rename(columns = {'Speicher':'i', 'Unnamed: 1':'E2P-Ratio'})
151
- # #df_excel = i.to_frame().reset_index(drop=True).merge(df_excel, how = 'left')
152
- # df_excel = df_excel.fillna(0)
153
- # df_excel = df_excel.set_index('i')
154
- # e2p_iSto = df_excel.iloc[:,0].to_xarray()
155
 
156
  # # Inflow for hydro reservoir
157
  # df_excel = pd.read_excel(url_excel, sheet_name = 'HydroInflow')
@@ -166,7 +166,7 @@ def load_data_from_excel(url_excel, write_to_pickle_flag = True):
166
  # Append parameters to the dictionary
167
  sets_dict['t'] = t
168
  sets_dict['i'] = i
169
- # sets_dict['iSto'] = iSto
170
  sets_dict['iConv'] = iConv
171
  # sets_dict['iPtG'] = iPtG
172
  sets_dict['iRes'] = iRes
@@ -185,7 +185,7 @@ def load_data_from_excel(url_excel, write_to_pickle_flag = True):
185
  params_dict['c_var_i'] = c_var_i
186
  params_dict['s_t_r_iRes'] = s_t_r_iRes
187
  params_dict['K_0_i'] = K_0_i
188
- # params_dict['e2p_iSto'] = e2p_iSto
189
  # params_dict['h_t'] = h_t
190
 
191
  if write_to_pickle_flag:
 
39
  df_excel = pd.read_excel(url_excel, sheet_name='Technologies')
40
  iRes = pd.Index(df_excel.iloc[0:4, 4], name='iRes')
41
 
42
+ df_excel = pd.read_excel(url_excel, sheet_name='Technologies')
43
+ iSto = pd.Index(df_excel.iloc[0:1, 6], name='iSto')
44
 
45
  # df_excel = pd.read_excel(url_excel, sheet_name='Technologies')
46
  # iPtG = pd.Index(df_excel.iloc[0:1, 8], name='iPtG')
 
145
  df_excel = df_excel.set_index('i')
146
  K_0_i = df_excel.iloc[:,0].to_xarray()
147
 
148
+ # Energy-to-power ratio storages
149
+ df_excel = pd.read_excel(url_excel, sheet_name = 'E2P')
150
+ df_excel = df_excel.rename(columns = {'Speicher':'i', 'Unnamed: 1':'E2P-Ratio'})
151
+ #df_excel = i.to_frame().reset_index(drop=True).merge(df_excel, how = 'left')
152
+ df_excel = df_excel.fillna(0)
153
+ df_excel = df_excel.set_index('i')
154
+ e2p_iSto = df_excel.iloc[:,0].to_xarray()
155
 
156
  # # Inflow for hydro reservoir
157
  # df_excel = pd.read_excel(url_excel, sheet_name = 'HydroInflow')
 
166
  # Append parameters to the dictionary
167
  sets_dict['t'] = t
168
  sets_dict['i'] = i
169
+ sets_dict['iSto'] = iSto
170
  sets_dict['iConv'] = iConv
171
  # sets_dict['iPtG'] = iPtG
172
  sets_dict['iRes'] = iRes
 
185
  params_dict['c_var_i'] = c_var_i
186
  params_dict['s_t_r_iRes'] = s_t_r_iRes
187
  params_dict['K_0_i'] = K_0_i
188
+ params_dict['e2p_iSto'] = e2p_iSto
189
  # params_dict['h_t'] = h_t
190
 
191
  if write_to_pickle_flag: