|
1 | 1 | # %% GET TOOLS |
2 | 2 |
|
3 | 3 | # Imports |
| 4 | +import matplotlib.gridspec |
4 | 5 | import matplotlib.pyplot as plt |
5 | 6 | import pandas as pd |
| 7 | +from matplotlib import cm |
6 | 8 | from matplotlib.ticker import PercentFormatter |
| 9 | +from matplotlib.colors import Normalize |
7 | 10 |
|
8 | 11 | from papers.Martin_Staadecker_Value_of_LDES_and_Factors.LDES_paper_graphs.util import ( |
9 | 12 | set_style, |
10 | 13 | get_set_e_scenarios, |
11 | 14 | ) |
12 | 15 | from switch_model.tools.graph.main import GraphTools |
13 | 16 |
|
14 | | - |
15 | 17 | # Prepare graph tools |
16 | 18 | tools = GraphTools(scenarios=get_set_e_scenarios()) |
17 | 19 | tools.pre_graphing(multi_scenario=True) |
|
21 | 23 | plt.close() |
22 | 24 | fig = plt.figure() |
23 | 25 | fig.set_size_inches(12, 12) |
24 | | -ax1 = fig.add_subplot(2, 2, 1) |
25 | | -ax2 = fig.add_subplot(2, 2, 2) |
26 | | -ax3 = fig.add_subplot(2, 2, 3) |
27 | | -ax4 = fig.add_subplot(2, 2, 4) |
| 26 | +gs = matplotlib.gridspec.GridSpec(2, 2, figure=fig) |
| 27 | +ax1 = fig.add_subplot(gs[0, 0]) |
| 28 | +ax2 = fig.add_subplot(gs[0, 1]) |
| 29 | +ax3 = fig.add_subplot(gs[1, :]) |
28 | 30 |
|
29 | 31 | # %% IMPACT ON TX AND GEN |
30 | 32 |
|
|
131 | 133 | ax.set_xlabel("WECC-wide storage capacity (TWh)") |
132 | 134 | ax.set_title("A. Impact of LDES on curtailment") |
133 | 135 | ax.tick_params(top=False, bottom=False, right=False, left=False) |
134 | | -# %% |
135 | | -plt.subplots_adjust( |
136 | | - hspace=0.2, wspace=0.25, left=0.07, right=0.97, top=0.95, bottom=0.07 |
| 136 | +# %% State of charge |
| 137 | +ax = ax3 |
| 138 | +ax.clear() |
| 139 | + |
| 140 | +freq = "1D" |
| 141 | + |
| 142 | +state_of_charge = tools.get_dataframe("StateOfCharge.csv") |
| 143 | +state_of_charge = state_of_charge.rename( |
| 144 | + {"STORAGE_GEN_TPS_2": "timepoint", "StateOfCharge": "value"}, axis=1 |
| 145 | +) |
| 146 | +state_of_charge = state_of_charge.groupby( |
| 147 | + ["scenario_name", "timepoint"], as_index=False |
| 148 | +).value.sum() |
| 149 | +state_of_charge.value *= 1e-6 # Convert from MWh to TWh |
| 150 | +state_of_charge = tools.transform.timestamp(state_of_charge, use_timepoint=True) |
| 151 | +state_of_charge = state_of_charge.set_index("datetime") |
| 152 | +state_of_charge = state_of_charge.groupby("scenario_name").resample(freq).value.mean() |
| 153 | +state_of_charge = state_of_charge.unstack("scenario_name").rename_axis( |
| 154 | + "Storage Capacity (TWh)", axis=1 |
137 | 155 | ) |
138 | 156 |
|
| 157 | +demand = tools.get_dataframe("loads.csv", from_inputs=True).rename( |
| 158 | + {"TIMEPOINT": "timepoint", "zone_demand_mw": "value"}, axis=1 |
| 159 | +) |
| 160 | +demand = demand[demand.scenario_name == 1.94] |
| 161 | +demand = demand.groupby("timepoint", as_index=False).value.sum() |
| 162 | +demand = tools.transform.timestamp(demand, use_timepoint=True) |
| 163 | +demand = demand.set_index("datetime")["value"] |
| 164 | +demand = demand.resample(freq).mean() |
| 165 | +demand = demand * 60 / demand.max() |
| 166 | + |
| 167 | +state_of_charge.plot( |
| 168 | + ax=ax, |
| 169 | + cmap="viridis", |
| 170 | + ylabel="WECC-wide stored energy (TWh, 24h mean)", |
| 171 | + xlabel="Time of year", |
| 172 | + legend=False, |
| 173 | +) |
| 174 | +plt.colorbar( |
| 175 | + cm.ScalarMappable(norm=Normalize(1.94, 64), cmap="viridis"), |
| 176 | + ax=ax, |
| 177 | + label="Storage Capacity (TWh)", |
| 178 | + fraction=0.1, |
| 179 | +) |
| 180 | + |
| 181 | +lines = ax.plot(demand, c="dimgray", linestyle="--", alpha=0.5) |
| 182 | +ax.legend(lines, ["Demand"]) |
| 183 | + |
| 184 | +ax.set_title("C. State of charge throughout the year") |
| 185 | +# %% |
| 186 | +plt.tight_layout() |
| 187 | + |
139 | 188 | # %% CALCULATIONS |
140 | 189 | cap_total = cap["Solar"] + cap["Wind"] |
141 | 190 | 1 - (cap_total / cap_total.iloc[0]) |
|
153 | 202 | # %% transmission |
154 | 203 | tx / tx.iloc[0] * 100 |
155 | 204 | (3 - 1.94) * 1000 / ((1 - tx.loc[3] / tx.iloc[0]) * 100) |
156 | | -# %% night time vs day time |
157 | | -df = daily_lmp.divide(daily_lmp["Noon"], axis=0) * 100 - 100 |
158 | | -df.min() |
159 | | -df.max() |
160 | | -# %% average drop in daily duals |
161 | | -df = daily_lmp.mean(axis=1) |
162 | | -df / df.iloc[0] - 1 |
163 | | -# daily_lmp / daily_lmp.iloc[0] - 1 |
164 | | -# %% night time drop |
165 | | -df = daily_lmp[["Midnight", "8pm", "4am"]].mean(axis=1) |
166 | | -(1 - df.loc[3] / df.iloc[0]) * 100 / ((3 - 1.94) * 10) |
|
0 commit comments