@@ -47,7 +47,8 @@ Columns in summary output include:
47
47
4. `data_type`, which is forecast or actual (data)
48
48
5. `lookahead` of the simulation in minutes
49
49
6. `revenue`, which is the total annual revenue of the simulated device in AUD
50
- 7. `mean_rel_gap`, which is the mean relative gap across all decision times
50
+ 7. `negative_revenue`, which is the total annual negative revenue (i.e. losses) of the simulated device in AUD
51
+ 8. `mean_rel_gap`, which is the mean relative gap across all decision times
51
52
52
53
# Arguments
53
54
@@ -64,6 +65,7 @@ function _summarise_simulations(
64
65
data:: Dict{String,Any} , formulation:: String , energy_capacity:: Float64
65
66
)
66
67
revenues = Float64[]
68
+ negative_revenues = Float64[]
67
69
bess_powers = Float64[]
68
70
data_types = String[]
69
71
lookaheads = Int64[]
@@ -74,10 +76,12 @@ function _summarise_simulations(
74
76
lookahead_df = df[df. lookahead_minutes .== lookahead, :]
75
77
lookahead_df = lookahead_df[lookahead_df. status .== " binding" , :]
76
78
revenue = sum (lookahead_df. revenue)
79
+ negative_revenue = sum (lookahead_df[lookahead_df. revenue .< 0.0 , :revenue ])
77
80
average_gap = mean (unique (lookahead_df, " decision_time" ). relative_gap)
78
81
bess_power = string (match (r" ([0-9\. ]*)MW" , split (key, " /" )[2 ]). captures[])
79
82
data_type = split (key, " /" )[1 ]
80
83
push! (revenues, float (revenue))
84
+ push! (negative_revenues, negative_revenue)
81
85
push! (lookaheads, lookahead)
82
86
push! (average_gaps, average_gap)
83
87
push! (bess_powers, parse (Float64, bess_power))
@@ -91,6 +95,7 @@ function _summarise_simulations(
91
95
:data_type => data_types,
92
96
:lookahead => string .(lookaheads),
93
97
:revenue => revenues,
98
+ :negative_revenue => negative_revenues,
94
99
:mean_rel_gap => average_gaps,
95
100
)
96
101
summary_data = sort (summary_data, " power_capacity" )
@@ -100,18 +105,18 @@ function _summarise_simulations(
100
105
end
101
106
102
107
@doc raw """
103
- Calculates values of perfect information and foresight as absolute values (in AUD) and as
108
+ Calculates values of perfect lookahead and information as absolute values (in AUD) and as
104
109
a percentage of perfect foresight revenue.
105
110
106
- **Value of perfect information **: What is the additional benefit (revenue) that a participant
111
+ **Value of perfect lookahead **: What is the additional benefit (revenue) that a participant
107
112
could gain if they were to know exactly what the market prices will be in the *lookahead
108
113
horizon*.
109
- * ``VPI = \t extrm{Revenue}_\t extrm{Actual Data Simulation} - \t extrm{Revenue}_\t extrm{Forecast Data Simulation}``
114
+ * ``VPL = \t extrm{Revenue}_\t extrm{Actual Data Simulation} - \t extrm{Revenue}_\t extrm{Forecast Data Simulation}``
110
115
111
- **Value of perfect foresight **: What is the additional benefit (revenue) that a participant
112
- could gain if they were to know exactly what the market prices will be *over the entire
113
- year*
114
- * ``VPF = \t extrm{Revenue}_\t extrm{Perfect Foresight} - \t extrm{Revenue}_\t extrm{Forecast Data Simulation}``
116
+ **Value of perfect information **: What is the additional benefit (revenue) that a
117
+ participant could gain if they were to know exactly what the market prices will be
118
+ *over the entire year*
119
+ * ``VPI = \t extrm{Revenue}_\t extrm{Perfect Foresight} - \t extrm{Revenue}_\t extrm{Forecast Data Simulation}``
115
120
116
121
N.B. This function assumes that the input `df` only has data that corresponds to a device
117
122
of a particular `energy_capacity`.
@@ -122,12 +127,12 @@ of a particular `energy_capacity`.
122
127
123
128
# Returns
124
129
125
- `DataFrame` with absolute values of perfect information and foresight , and the same values
130
+ `DataFrame` with absolute values of perfect lookahead and information , and the same values
126
131
as a percentage of perfect foresight revenue.
127
132
"""
128
- function calculate_vpi_vpf (df:: DataFrame )
129
- (v_pi_abs, v_pf_abs ) = (Float64[], Float64[])
130
- (v_pi_percentage, v_pf_percentage ) = (Float64[], Float64[])
133
+ function calculate_vpl_vpi (df:: DataFrame )
134
+ (v_pl_abs, v_pi_abs ) = (Float64[], Float64[])
135
+ (v_pl_percentage, v_pi_percentage ) = (Float64[], Float64[])
131
136
(power_caps, data) = (Float64[], String[])
132
137
actual_caps = unique (df[df. data_type .== " actual" , :power_capacity ])
133
138
forecast_caps = unique (df[df. data_type .== " forecast" , :power_capacity ])
@@ -139,45 +144,45 @@ function calculate_vpi_vpf(df::DataFrame)
139
144
cap_mask = df. power_capacity .== cap
140
145
actual_mask = df. data_type .== " actual"
141
146
forecast_mask = df. data_type .== " forecast"
142
- pf_rev = df[
147
+ pi_rev = df[
143
148
cap_mask .& forecast_mask .& (df. lookahead .== " Perfect Foresight" ),
144
149
:revenue ,
145
150
]
146
- pi_rev = df[cap_mask .& actual_mask .& lk_mask, :revenue ]
151
+ pl_rev = df[cap_mask .& actual_mask .& lk_mask, :revenue ]
152
+ v_pl = pl_rev - df[cap_mask .& forecast_mask .& lk_mask, :revenue ]
147
153
v_pi = pi_rev - df[cap_mask .& forecast_mask .& lk_mask, :revenue ]
148
- v_pf = pf_rev - df[cap_mask .& forecast_mask .& lk_mask, :revenue ]
149
- v_pi_percentage_pf = @. v_pi / pf_rev * 100
150
- v_pf_percentage_pf = @. v_pf / pf_rev * 100
154
+ v_pl_percentage_pi = @. v_pl / pi_rev * 100
155
+ v_pi_percentage_pi = @. v_pi / pi_rev * 100
151
156
push! (power_caps, cap)
152
157
push! (data, lookahead)
158
+ push! (v_pl_abs, v_pl[])
153
159
push! (v_pi_abs, v_pi[])
154
- push! (v_pf_abs, v_pf[])
155
- push! (v_pi_percentage, v_pi_percentage_pf[])
156
- push! (v_pf_percentage, v_pf_percentage_pf[])
160
+ push! (v_pl_percentage, v_pl_percentage_pi[])
161
+ push! (v_pi_percentage, v_pi_percentage_pi[])
157
162
end
158
163
end
159
164
return DataFrame (
160
165
:formulation => fill (unique (df. formulation)[], length (power_caps)),
161
166
:energy_capacity => fill (unique (df. energy_capacity)[], length (power_caps)),
162
167
:power_capacity => power_caps,
163
168
:lookahead => data,
169
+ :vpl_abs => v_pl_abs,
164
170
:vpi_abs => v_pi_abs,
165
- :vpf_abs => v_pf_abs ,
171
+ :vpl_per => v_pl_percentage ,
166
172
:vpi_per => v_pi_percentage,
167
- :vpf_per => v_pf_percentage,
168
173
)
169
174
end
170
175
171
176
"""
172
177
Summarises results for each simulated formulation and then calculates values of perfect
173
- information and foresight .
178
+ lookahead and information .
174
179
175
180
For each state, this function cycles through each simulated formulation and:
176
181
177
182
1. Calculates summary results (i.e. annual revenue and mean relative gap)
178
- 2. Calculates the value of perfect information and value of perfect foresight
183
+ 2. Calculates the value of perfect lookahead and value of perfect information
179
184
180
- For a single state, the VPIs and VPFs across simulated formulations are then released
185
+ For a single state, the VPLs and VPIs across simulated formulations are then released
181
186
information a JLD2 file in the `results` folder, along with summary results for each
182
187
simulated formulation.
183
188
@@ -186,11 +191,11 @@ simulated formulation.
186
191
187
192
# Returns
188
193
189
- `Dict` mapping each state to `DataFrame` with VPI and VPF for each formulation and
194
+ `Dict` mapping each state to `DataFrame` with VPL and VPI for each formulation and
190
195
lookahead.
191
196
"""
192
- function calculate_summaries_and_vpi_vpf_across_scenarios (sim_folder:: String )
193
- function _calculate_summary_vpi_vpf_for_formulation (
197
+ function calculate_summaries_and_vpl_vpi_across_scenarios (sim_folder:: String )
198
+ function _calculate_summary_vpl_vpi_for_formulation (
194
199
sim_folder:: String ,
195
200
formulation:: String ,
196
201
file:: String ,
@@ -201,31 +206,31 @@ function calculate_summaries_and_vpi_vpf_across_scenarios(sim_folder::String)
201
206
data = load (joinpath (results_path, file))
202
207
@info " Calculating summary information for $state $formulation "
203
208
summary = _summarise_simulations (data, formulation, energy)
204
- @info " Calculating VPI and VPF for $state $formulation "
205
- return summary, calculate_vpi_vpf (summary)
209
+ @info " Calculating VPL and VPI for $state $formulation "
210
+ return summary, calculate_vpl_vpi (summary)
206
211
end
207
212
208
213
save_path = joinpath (" results" , " data" )
209
214
if ! isdir (save_path)
210
215
mkpath (save_path)
211
216
end
212
217
categorisation = _categorise_simulation_results (sim_folder)
213
- states_vpi_vpf = Dict {String,DataFrame} ()
218
+ states_vpl_vpi = Dict {String,DataFrame} ()
214
219
for state in keys (categorisation)
215
220
summary_data = Dict {String,DataFrame} ()
216
- vpi_vpf_data = DataFrame[]
221
+ vpl_vpi_data = DataFrame[]
217
222
formulation_results = categorisation[state]
218
223
for (formulation, results) in pairs (formulation_results)
219
224
if length (results) == 1
220
225
file = results[]
221
226
energy = parse (
222
227
Float64, match (r" [A-Z]{2,3}_([0-9\. ]*)MWh_.*" , file). captures[]
223
228
)
224
- (summary, vpi_vpf ) = _calculate_summary_vpi_vpf_for_formulation (
229
+ (summary, vpl_vpi ) = _calculate_summary_vpl_vpi_for_formulation (
225
230
sim_folder, formulation, file, energy, state
226
231
)
227
- vpi_vpf [! , :param ] = fill (missing , size (vpi_vpf , 1 ))
228
- push! (vpi_vpf_data, vpi_vpf )
232
+ vpl_vpi [! , :param ] = fill (missing , size (vpl_vpi , 1 ))
233
+ push! (vpl_vpi_data, vpl_vpi )
229
234
summary_data[" $(formulation) " ] = summary
230
235
else
231
236
for file in results
@@ -234,11 +239,11 @@ function calculate_summaries_and_vpi_vpf_across_scenarios(sim_folder::String)
234
239
)
235
240
energy = parse (Float64, energy_param_capture. captures[1 ])
236
241
param = string (energy_param_capture. captures[2 ])
237
- (summary, vpi_vpf ) = _calculate_summary_vpi_vpf_for_formulation (
242
+ (summary, vpl_vpi ) = _calculate_summary_vpl_vpi_for_formulation (
238
243
sim_folder, formulation, file, energy, state
239
244
)
240
- vpi_vpf [! , :param ] = fill (param, size (vpi_vpf , 1 ))
241
- push! (vpi_vpf_data, vpi_vpf )
245
+ vpl_vpi [! , :param ] = fill (param, size (vpl_vpi , 1 ))
246
+ push! (vpl_vpi_data, vpl_vpi )
242
247
summary_data[" $(formulation) /$(param) " ] = summary
243
248
end
244
249
end
@@ -249,12 +254,12 @@ function calculate_summaries_and_vpi_vpf_across_scenarios(sim_folder::String)
249
254
f[key] = value
250
255
end
251
256
end
252
- state_vpi_vpf = vcat (vpi_vpf_data ... )
253
- @info " Saving VPI and VPF data for $state "
254
- jldopen (joinpath (save_path, " vpi_vpf .jld2" ), " w" ; compress= true ) do f
255
- f[" $(state) " ] = state_vpi_vpf
257
+ state_vpl_vpi = vcat (vpl_vpi_data ... )
258
+ @info " Saving VPL and VPI data for $state "
259
+ jldopen (joinpath (save_path, " vpl_vpi .jld2" ), " w" ; compress= true ) do f
260
+ f[" $(state) " ] = state_vpl_vpi
256
261
end
257
- states_vpi_vpf [state] = state_vpi_vpf
262
+ states_vpl_vpi [state] = state_vpl_vpi
258
263
end
259
- return states_vpi_vpf
264
+ return states_vpl_vpi
260
265
end
0 commit comments