junglegobs / ASoSEPOC

Interaction betwen resource adequacy and security of supply task in the EPOC project.
1 stars 0 forks source link

No reserve shedding takes place #6

Closed junglegobs closed 2 years ago

junglegobs commented 2 years ago

This could be due to excessive renewable curtailment, i.e. renewables are being curtailed just to ensure grid feasibility. To be verified.

junglegobs commented 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...

junglegobs commented 2 years ago

I'm going to move discussion to #7

junglegobs commented 2 years ago

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]),
)
junglegobs commented 2 years ago

image

Fuck... no load shedding...

junglegobs commented 2 years ago

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.

junglegobs commented 2 years ago

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
junglegobs commented 2 years ago

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:

image

image

If reserve shedding is not allowed, then there is a lot of load shedding:

image

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).

junglegobs commented 2 years ago

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

image

image

junglegobs commented 2 years ago

Summary:

junglegobs commented 2 years ago
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
junglegobs commented 2 years ago

Closing this as not relevant anymore