run.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import pandas as pd
  2. import numpy as np
  3. from matplotlib import pyplot as plt
  4. import matplotlib.dates as mdates
  5. import yaml
  6. from mix_simul.scenarios import Scenario
  7. with open("scenarios/rte.yml", 'r') as f:
  8. rte = yaml.load(f, Loader=yaml.FullLoader)
  9. potential = pd.read_parquet("data/potential.parquet")
  10. potential = potential.loc['1985-01-01 00:00:00':'2015-01-01 00:00:00', :]
  11. potential.fillna(0, inplace=True)
  12. begin = "2012-01-01"
  13. end = "2015-01-01"
  14. flexibility = False
  15. potential = potential.loc[(
  16. slice(f'{begin} 00:00:00', f'{end} 00:00:00'), 'FR'), :]
  17. # intermittent sources potential
  18. p = potential[["onshore", "offshore", "solar"]].to_xarray().to_array()
  19. p = np.insert(p, 3, 0.68, axis=0) # nuclear power-like
  20. times = potential.index.get_level_values(0)
  21. fig, axes = plt.subplots(nrows=6, ncols=2, sharex="col", sharey=True)
  22. w, h = fig.get_size_inches()
  23. fig.set_figwidth(w*1.5)
  24. fig.set_figheight(h*1.5)
  25. fig_storage, axes_storage = plt.subplots(nrows=6, ncols=2, sharex="col", sharey=True)
  26. fig_storage.set_figwidth(w*1.5)
  27. fig_storage.set_figheight(h*1.5)
  28. fig_dispatch, axes_dispatch = plt.subplots(nrows=6, ncols=2, sharex="col", sharey=True)
  29. fig_dispatch.set_figwidth(w*1.5)
  30. fig_dispatch.set_figheight(h*1.5)
  31. date_fmt = mdates.DateFormatter('%d/%m')
  32. # for step in np.linspace(start, stop, 2050-2022, True)[::-1]:
  33. row = 0
  34. for scenario in rte:
  35. rte[scenario]["flexibility_power"] = 0
  36. scenario_model = Scenario(**rte[scenario])
  37. S, load, production, gap, storage, dp = scenario_model.run(times, p)
  38. print(f"{scenario}:", S, gap.max(), np.quantile(gap, 0.95))
  39. print(f"exports: {np.minimum(np.maximum(-gap, 0), 39).sum()/1000} TWh; imports: {np.minimum(np.maximum(gap, 0), 39).sum()/1000} TWh")
  40. print(f"dispatchable: " + ", ".join([f"{dp[i].sum()/1000:.2f} TWh" for i in range(dp.shape[0])]))
  41. potential['load'] = load
  42. potential['production'] = production
  43. potential['available'] = production-np.diff(storage.sum(axis=0), append=0)
  44. for i in range(3):
  45. potential[f"storage_{i}"] = np.diff(storage[i,:], append=0)#storage[i,:]/1000
  46. potential[f"storage_{i}"] = storage[i,:]/1000
  47. for i in range(dp.shape[0]):
  48. potential[f"dispatch_{i}"] = dp[i,:]
  49. potential["dispatch"] = dp.sum(axis=0)
  50. data = [
  51. potential.loc[(slice('2013-12-01 00:00:00',
  52. '2014-01-01 00:00:00'), 'FR'), :],
  53. potential.loc[(slice('2013-06-01 00:00:00',
  54. '2013-07-01 00:00:00'), 'FR'), :]
  55. ]
  56. months = [
  57. "Février",
  58. "Juin"
  59. ]
  60. labels = [
  61. "load (GW)",
  62. "production (GW)",
  63. "available power (production-storage) (GW)",
  64. "power deficit"
  65. ]
  66. labels_storage = [
  67. "Batteries (TWh)",
  68. "STEP (TWh)",
  69. "P2G (TWh)"
  70. ]
  71. labels_dispatch = [
  72. "Hydro (GW)",
  73. "Biomass (GW)",
  74. "Thermal (GW)"
  75. ]
  76. for col in range(2):
  77. ax = axes[row, col]
  78. ax.plot(data[col].index.get_level_values(0), data[col]
  79. ["load"], label="adjusted load (GW)", lw=1)
  80. ax.plot(data[col].index.get_level_values(0), data[col]
  81. ["production"], label="production (GW)", ls="dotted", lw=1)
  82. ax.plot(data[col].index.get_level_values(0), data[col]["available"],
  83. label="available power (production-d(storage)/dt) (GW)", lw=1)
  84. ax.fill_between(
  85. data[col].index.get_level_values(0),
  86. data[col]["available"],
  87. data[col]["load"],
  88. where=data[col]["load"] > data[col]["available"],
  89. color='red',
  90. alpha=0.15
  91. )
  92. ax.xaxis.set_major_formatter(date_fmt)
  93. ax.text(
  94. 0.5, 0.87, f"Scénario {scenario} ({months[col]})", ha='center', transform=ax.transAxes)
  95. ax.set_ylim(25, 225)
  96. ax = axes_storage[row, col]
  97. for i in np.arange(3):
  98. if i == 2:
  99. base = 0
  100. else:
  101. base = np.sum([data[col][f"storage_{j}"] for j in np.arange(i+1,3)], axis=0)
  102. ax.fill_between(data[col].index.get_level_values(0), base, base+data[col]
  103. [f"storage_{i}"], label=f"storage {i}", alpha=0.5)
  104. ax.plot(data[col].index.get_level_values(0), base+data[col]
  105. [f"storage_{i}"], label=f"storage {i}", lw=0.25)
  106. ax.xaxis.set_major_formatter(date_fmt)
  107. ax.text(
  108. 0.5, 0.87, f"Scénario {scenario} ({months[col]})", ha='center', transform=ax.transAxes)
  109. ax = axes_dispatch[row, col]
  110. for i in range(dp.shape[0]):
  111. if i == 0:
  112. base = 0
  113. else:
  114. base = np.sum([data[col][f"dispatch_{j}"] for j in np.arange(i)], axis=0)
  115. ax.fill_between(data[col].index.get_level_values(0), base, base+data[col]
  116. [f"dispatch_{i}"], label=f"dispatch {i}", alpha=0.5)
  117. ax.plot(data[col].index.get_level_values(0), base+data[col]
  118. [f"dispatch_{i}"], label=f"dispatch {i}", lw=0.25)
  119. ax.xaxis.set_major_formatter(date_fmt)
  120. ax.text(
  121. 0.5, 0.87, f"Scénario {scenario} ({months[col]})", ha='center', transform=ax.transAxes)
  122. row += 1
  123. for label in axes[-1, 0].get_xmajorticklabels() + axes[-1, 1].get_xmajorticklabels():
  124. label.set_rotation(30)
  125. label.set_horizontalalignment("right")
  126. for label in axes_storage[-1, 0].get_xmajorticklabels() + axes_storage[-1, 1].get_xmajorticklabels():
  127. label.set_rotation(30)
  128. label.set_horizontalalignment("right")
  129. for label in axes_dispatch[-1, 0].get_xmajorticklabels() + axes_dispatch[-1, 1].get_xmajorticklabels():
  130. label.set_rotation(30)
  131. label.set_horizontalalignment("right")
  132. flex = "With" if flexibility else "Without"
  133. plt.subplots_adjust(wspace=0, hspace=0)
  134. fig.suptitle(f"Simulations based on {begin}--{end} weather data.\n{flex} consumption flexibility; no nuclear seasonality (unrealistic)")
  135. fig.text(1, 0, 'Lucas Gautheron', ha="right")
  136. fig.legend(labels, loc='lower right', bbox_to_anchor=(1, -0.1),
  137. ncol=len(labels), bbox_transform=fig.transFigure)
  138. fig.savefig("output.png", bbox_inches="tight", dpi=200)
  139. fig_storage.suptitle(f"Simulations based on {begin}--{end} weather data.\n{flex} consumption flexibility; no nuclear seasonality (unrealistic)")
  140. fig_storage.text(1, 0, 'Lucas Gautheron', ha="right")
  141. fig_storage.legend(labels_storage, loc='lower right', bbox_to_anchor=(1, -0.1),
  142. ncol=len(labels_storage), bbox_transform=fig_storage.transFigure)
  143. fig_storage.savefig("output_storage.png", bbox_inches="tight", dpi=200)
  144. fig_dispatch.suptitle(f"Simulations based on {begin}--{end} weather data.\n{flex} consumption flexibility; no nuclear seasonality (unrealistic)")
  145. fig_dispatch.text(1, 0, 'Lucas Gautheron', ha="right")
  146. fig_dispatch.legend(labels_dispatch, loc='lower right', bbox_to_anchor=(1, -0.1),
  147. ncol=len(labels_dispatch), bbox_transform=fig_dispatch.transFigure)
  148. fig_dispatch.savefig("output_dispatch.png", bbox_inches="tight", dpi=200)
  149. plt.show()