Closed junglegobs closed 2 years ago
I added reserve provision costs to see what happens:
opts["reserve_provision_cost"] = 100.0
sum(gep[:rsL⁺]) = 15059.392348898957
sum(gep[:loadShedding]) = 8195.679305717125
opts["reserve_provision_cost"] = 50.0
sum(gep[:rsL⁺]) = 8230.892347448875
sum(gep[:loadShedding]) = 8195.679306151758
opts["reserve_provision_cost"] = 200.0
sum(gep[:rsL⁺]) = 22558.00495157286
sum(gep[:loadShedding]) = 8195.679303862
So indeed, it seems that the model is filling reserves from RES curtailment.
Taking a step back for a minute, this is a fairly crazy situation - load shedding is occurring in the day ahead due partly to congestion from RES, and a significant portion of operating reserves is being provided by RES. Clearly, including network constraints in the "reserve activation" stage would be beneficial...
I'm going to move discussion to #7
Running the code below gives me the following solution:
3×3 DataFrame
Row │ Reserve shedding limit Reserve Shedding Load shedding
│ Float64 Float64 Float64
─────┼─────────────────────────────────────────────────────────
1 │ 1.0 1259.58 8.28134e-8
2 │ 0.5 1259.58 5.37774e-9
3 │ 0.0 0.0 6.96272e-10
So annoyingly, I know have the opposite solution - load shedding does not take place though reserve shedding does. Then again, this is a very "flexible" model, so congestion may be less of an issue. I will double check to see what my full year model says (in terms of load shedding), but also constrain my storage state of charge.
include(joinpath(@__DIR__, "..", "intro.jl"))
sn = script_name(@__FILE__)
mkrootdirs(plotsdir(sn))
rm(simsdir(sn); force=true, recursive=true)
opts = options_diff_days(sn)[4]
rm(opts["save_path"]; force=true, recursive=true)
opts["unit_commitment_type"] = "none"
opts["initial_state_of_charge"] = 0.0
opts["absolute_limits_on_nodal_imbalance"] = true
opts["prevent_simultaneous_charge_and_discharge"] = false
opts["upward_reserve_levels_included_in_redispatch"] = 1:10
opts["downward_reserve_levels_included_in_redispatch"] = 1:10
RSL_vec = [1.0, 0.5, 0.0]
opts_vec = [
merge(
opts,
Dict(
"reserve_shedding_limit" => v,
"save_path" => opts["save_path"] * "_RSL=_$v",
),
) for v in RSL_vec
]
gep = run_GEPPR(opts_vec[1])
gep_vec = run_GEPPR(opts_vec)
df = DataFrame(
"Reserve shedding limit" => RSL_vec,
"Reserve Shedding" => sum.([gep[:rsL⁺] for gep in gep_vec]),
"Load shedding" => sum.([gep[:loadShedding] for gep in gep_vec]),
)
Fuck... no load shedding...
Ok, but if I reduce the flexibility (add UC, no simult charge/discharge) I do have shedding (but reserve shedding limit doesn't affect this!!!):
3×3 DataFrame
Row │ Reserve shedding limit Reserve Shedding Load shedding
│ Float64 Float64 Float64
─────┼─────────────────────────────────────────────────────────
1 │ 1.0 135.827 1669.26
2 │ 0.5 135.827 1669.26
3 │ 0.0 0.0 1669.26
Before going into convex hull shit, should double check that I removing the network has the desired effect.
Hmmm... if you remove the network, this happens (should double check what happens if you make the line capacities -> infty)
3×3 DataFrame
Row │ Reserve shedding limit Reserve Shedding Load shedding
│ Float64 Float64 Float64
─────┼─────────────────────────────────────────────────────────
1 │ 1.0 0.0 1669.26
2 │ 0.5 0.0 1669.26
3 │ 0.0 0.0 1669.26
So I did that, + multiplied the loads by a factor of 1.5 and got this:
julia> df
3×3 DataFrame
Row │ Reserve shedding limit Reserve Shedding Load shedding
│ Float64 Float64 Float64
─────┼─────────────────────────────────────────────────────────
1 │ 1.0 26555.3 9190.43
2 │ 0.5 19002.1 16672.1
3 │ 0.0 0.0 34861.0
Below is the dispatch for when reserve shedding is allowed:
If reserve shedding is not allowed, then there is a lot of load shedding:
So the model is doing what I expect it to do, shedding reserves as much as it can (if this is permitted) when there is load shedding in day ahead and shedding reserves to avoid load shedding (if this is permitted).
Ok, so this is starting to make sense. If no network constraints are considered in the reserve activation, then some reserve shedding takes place but not much:
julia> df
3×3 DataFrame
Row │ Reserve shedding limit Reserve Shedding Load shedding
│ Float64 Float64 Float64
─────┼─────────────────────────────────────────────────────────
1 │ 1.0 29604.8 15482.9
2 │ 0.5 28096.1 16950.6
3 │ 0.0 0.0 42008.7
Summary:
opts = options_diff_days(sn)[4]
rm(opts["save_path"]; force=true, recursive=true)
opts["copperplate"] = true
opts["load_multiplier"] = 1.5
opts["initial_state_of_charge"] = 0.0
# ...
julia> df
3×3 DataFrame
Row │ Reserve shedding limit Reserve Shedding Load shedding
│ Float64 Float64 Float64
─────┼─────────────────────────────────────────────────────────
1 │ 1.0 26610.0 9190.43
2 │ 0.5 19002.1 16672.1
3 │ 0.0 0.0 34861.0
And the same but with network constraints:
julia> df
3×3 DataFrame
Row │ Reserve shedding limit Reserve Shedding Load shedding
│ Float64 Float64 Float64
─────┼─────────────────────────────────────────────────────────
1 │ 1.0 29604.8 15482.9
2 │ 0.5 28096.1 16950.6
3 │ 0.0 0.0 42008.7
Closing this as not relevant anymore
This could be due to excessive renewable curtailment, i.e. renewables are being curtailed just to ensure grid feasibility. To be verified.