Skip to content

Commit

Permalink
Add can_retire validation for multi-stage optimization (#683)
Browse files Browse the repository at this point in the history
  • Loading branch information
lbonaldo authored Apr 19, 2024
1 parent aa0e0ef commit 1102d32
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added versioned doc-pages for v0.3.6 and v0.4.0
- Add constraint in mga to compute total capacity in each zone from a given technology type (#681)
- New settings parameter MGAAnnualGeneration to switch between different MGA formulations (#681)
- Add validation for `Can_Retire` column in multi-stage GenX since the current implementation
does not allow a resource to switch from can_retire = 0 to can_retire = 1 between stages. (#683)

### Fixed
- Set MUST_RUN=1 for RealSystemExample/small_hydro plants (#517).
Expand Down
4 changes: 4 additions & 0 deletions src/case_runners/case_runner.jl
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ function run_genx_case_multistage!(case::AbstractString, mysetup::Dict, optimize
model_dict[t] = generate_model(mysetup, inputs_dict[t], OPTIMIZER)
end

# check that resources do not switch from can_retire = 0 to can_retire = 1 between stages
validate_can_retire_multistage(
inputs_dict, mysetup["MultiStageSettingsDict"]["NumStages"])

### Solve model
println("Solving Model")

Expand Down
34 changes: 34 additions & 0 deletions src/multi_stage/configure_multi_stage_inputs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -217,3 +217,37 @@ function configure_multi_stage_inputs(inputs_d::Dict,

return inputs_d
end

@doc raw"""
validate_can_retire_multistage(inputs_dict::Dict, num_stages::Int)
This function validates that all the resources do not switch from havig `can_retire = 0` to `can_retire = 1` during the multi-stage optimization.
# Arguments
- `inputs_dict::Dict`: A dictionary containing the inputs for each stage.
- `num_stages::Int`: The number of stages in the multi-stage optimization.
# Returns
- Throws an error if a resource switches from `can_retire = 0` to `can_retire = 1` between stages.
"""
function validate_can_retire_multistage(inputs_dict::Dict, num_stages::Int)
for stage in 2:num_stages # note: loop starts from 2 because we are comparing stage t with stage t-1
can_retire_current = can_retire.(inputs_dict[stage]["RESOURCES"])
can_retire_previous = can_retire.(inputs_dict[stage - 1]["RESOURCES"])

# Check if any resource switched from can_retire = 0 to can_retire = 1 between stage t-1 and t
if any(can_retire_current .- can_retire_previous .> 0)
# Find the resources that switched from can_retire = 0 to can_retire = 1 and throw an error
retire_switch_ids = findall(can_retire_current .- can_retire_previous .> 0)
resources_switched = inputs_dict[stage]["RESOURCES"][retire_switch_ids]
for resource in resources_switched
@warn "Resource `$(resource_name(resource))` with id = $(resource_id(resource)) switched " *
"from can_retire = 0 to can_retire = 1 between stages $(stage - 1) and $stage"
end
msg = "Current implementation of multi-stage optimization does not allow resources " *
"to switch from can_retire = 0 to can_retire = 1 between stages."
error(msg)
end
end
return nothing
end
70 changes: 70 additions & 0 deletions test/test_multistage.jl
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,74 @@ end

test_update_cumulative_min_ret!()

function test_can_retire_validation()
@testset "No resources switch from can_retire = 0 to can_retire = 1" begin
inputs = Dict{Int, Dict}()
inputs[1] = Dict("RESOURCES" => [
GenX.Thermal(Dict(:resource => "thermal", :id => 1,
:can_retire => 1)),
GenX.Vre(Dict(:resource => "vre", :id => 2,
:can_retire => 1)),
GenX.Hydro(Dict(:resource => "hydro", :id => 3,
:can_retire => 1)),
GenX.FlexDemand(Dict(:resource => "flex_demand", :id => 4,
:can_retire => 1))])
inputs[2] = Dict("RESOURCES" => [
GenX.Thermal(Dict(:resource => "thermal", :id => 1,
:can_retire => 0)),
GenX.Vre(Dict(:resource => "vre", :id => 2,
:can_retire => 1)),
GenX.Hydro(Dict(:resource => "hydro", :id => 3,
:can_retire => 1)),
GenX.FlexDemand(Dict(:resource => "flex_demand", :id => 4,
:can_retire => 1))])
inputs[3] = Dict("RESOURCES" => [
GenX.Thermal(Dict(:resource => "thermal", :id => 1,
:can_retire => 0)),
GenX.Vre(Dict(:resource => "vre", :id => 2,
:can_retire => 0)),
GenX.Hydro(Dict(:resource => "hydro", :id => 3,
:can_retire => 1)),
GenX.FlexDemand(Dict(:resource => "flex_demand", :id => 4,
:can_retire => 1))])
@test isnothing(GenX.validate_can_retire_multistage(inputs, 3))
end

@testset "One resource switches from can_retire = 0 to can_retire = 1" begin
inputs = Dict{Int, Dict}()
inputs[1] = Dict("RESOURCES" => [
GenX.Thermal(Dict(:resource => "thermal", :id => 1,
:can_retire => 0)),
GenX.Vre(Dict(:resource => "vre", :id => 2,
:can_retire => 0)),
GenX.Hydro(Dict(:resource => "hydro", :id => 3,
:can_retire => 0)),
GenX.FlexDemand(Dict(:resource => "flex_demand", :id => 4,
:can_retire => 1))])
inputs[2] = Dict("RESOURCES" => [
GenX.Thermal(Dict(:resource => "thermal", :id => 1,
:can_retire => 0)),
GenX.Vre(Dict(:resource => "vre", :id => 2,
:can_retire => 0)),
GenX.Hydro(Dict(:resource => "hydro", :id => 3,
:can_retire => 1)),
GenX.FlexDemand(Dict(:resource => "flex_demand", :id => 4,
:can_retire => 1))])
inputs[3] = Dict("RESOURCES" => [
GenX.Thermal(Dict(:resource => "thermal", :id => 1,
:can_retire => 0)),
GenX.Vre(Dict(:resource => "vre", :id => 2,
:can_retire => 0)),
GenX.Hydro(Dict(:resource => "hydro", :id => 3,
:can_retire => 1)),
GenX.FlexDemand(Dict(:resource => "flex_demand", :id => 4,
:can_retire => 1))])
@test_throws ErrorException GenX.validate_can_retire_multistage(inputs, 3)
end
end

with_logger(ConsoleLogger(stderr, Logging.Error)) do
test_can_retire_validation()
end

end # module TestMultiStage

0 comments on commit 1102d32

Please sign in to comment.