Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/src/User_Guide/model_input.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,8 @@ Each file contains cost and performance parameters for various generators and ot
---
|**Column Name** | **Description**|
| :------------ | :-----------|
|Min\_Power |[0,1], The minimum generation level for a unit as a fraction of total capacity. This value cannot be higher than the smallest time-dependent CF value for a resource in `Generators_variability.csv`.|
|Min\_Flow |[0,1], The minimum generation level for a unit as a fraction of total capacity. **Note**: setting a value greater than the time-dependent CF values for a resource in `Generators_variability.csv` can result in an infeasible model, because the model might not be able to generate enough power and/or discharge enough water to meet the minimum flow requirement. Always double check the variability data before running the model.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very minor, but can you change because the model might not be able to generate to because the unit might not be able to generate?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

of course!

|Min\_Power |[0,1], **DEPRECATED** (use `Min_Flow` instead). Retained for backwards compatibility; behaves identically to `Min_Flow`.
|Ramp\_Up\_Percentage |[0,1], Maximum increase in power output from between two periods (typically hours), reported as a fraction of nameplate capacity.|
|Ramp\_Dn\_Percentage |[0,1], Maximum decrease in power output from between two periods (typically hours), reported as a fraction of nameplate capacity.|
|Hydro\_Energy\_to\_Power\_Ratio |The rated number of hours of reservoir hydro storage at peak discharge power output. (hours). |
Expand Down
6 changes: 5 additions & 1 deletion src/model/resources/hydro/hydro_res.jl
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ function hydro_res!(EP::Model, inputs::Dict, setup::Dict)
reserves_term = @expression(EP, [y in HYDRO_RES, t in 1:T], 0)
regulation_term = @expression(EP, [y in HYDRO_RES, t in 1:T], 0)

# precompute min flow values for all hydro resources for efficiency
# Note: this will print the deprecation warning only once for each resource
min_flow_values = map(y -> min_flow(gen[y]), HYDRO_RES)

if setup["OperationalReserves"] > 0
HYDRO_RES_REG = intersect(HYDRO_RES, inputs["REG"]) # Set of reservoir hydro resources with regulation reserves
HYDRO_RES_RSV = intersect(HYDRO_RES, inputs["RSV"]) # Set of reservoir hydro resources with spinning reserves
Expand Down Expand Up @@ -160,7 +164,7 @@ function hydro_res!(EP::Model, inputs::Dict, setup::Dict)
ramp_down_fraction(gen[y]) * EP[:eTotalCap][y]
# Minimum streamflow running requirements (power generation and spills must be >= min value) in all hours
cHydroMinFlow[y in HYDRO_RES, t in 1:T],
EP[:vP][y, t] + EP[:vSPILL][y, t] >= min_power(gen[y]) * EP[:eTotalCap][y]
EP[:vP][y, t] + EP[:vSPILL][y, t] >= min_flow_values[y] * EP[:eTotalCap][y]
# DEV NOTE: When creating new hydro inputs, should rename Min_Power with Min_flow or similar for clarity since this includes spilled water as well

# Maximum discharging rate must be less than power rating OR available stored energy at start of hour, whichever is less
Expand Down
22 changes: 21 additions & 1 deletion src/model/resources/resources.jl
Original file line number Diff line number Diff line change
Expand Up @@ -717,8 +717,8 @@ function efficiency_down(r::T) where {T <: Union{Hydro, Storage}}
end

# Ramp up and down
min_power(r::Union{Electrolyzer, Thermal}) = get(r, :min_power, default_zero)
const VarPower = Union{Electrolyzer, Hydro, Thermal}
min_power(r::VarPower) = get(r, :min_power, default_zero)
ramp_up_fraction(r::VarPower) = get(r, :ramp_up_percentage, default_percent)
ramp_down_fraction(r::VarPower) = get(r, :ramp_dn_percentage, default_percent)

Expand Down Expand Up @@ -853,6 +853,26 @@ end
Returns the indices of all hydro resources in the vector `rs`.
"""
hydro(rs::Vector{T}) where {T <: AbstractResource} = findall(r -> isa(r, Hydro), rs)
# deprecate min_power(r::Hydro) in favor of min_flow(r::Hydro)
# TODO: remove this in the next breaking release
function min_power(r::Hydro)
Base.depwarn("`min_power(r::Hydro)` is deprecated, use `min_flow(r::Hydro)` instead.", :min_power, force = true)
return get(r, :min_power, default_zero)
end
function min_flow(r::Hydro)
if haskey(r, :min_flow) && haskey(r, :min_power)
@warn "Both `min_flow` and `min_power` are defined for resource $(resource_name(r)). Using `min_flow`."
Comment thread
gschivley marked this conversation as resolved.
return r.min_flow
elseif haskey(r, :min_flow)
return r.min_flow
# if only min_power is defined, use it and warn the user
elseif haskey(r, :min_power)
@warn "Column `min_power` is deprecated, column `min_flow` will replace it soon, please update your input data."
return r.min_power
else
return default_zero
end
end

# THERMAL interface
"""
Expand Down
34 changes: 34 additions & 0 deletions test/test_load_resource_data.jl
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,35 @@ function test_resource_specific_attributes(gen, dfGen, inputs)
dfGen[rs, :hydro_energy_to_power_ratio]
end

function test_min_power_deprecation(gen, dfGen)
hydro_res = GenX.hydro(gen)
# 1. min_power should still work
@test GenX.min_power.(gen[hydro_res]) == dfGen[hydro_res, :min_power]
@test GenX.min_power.(gen[hydro_res]) == [0.117, 0.18, 0.402]
# 2. min_power should throw a deprecation warning
@test_logs (:warn, "`min_power(r::Hydro)` is deprecated, use `min_flow(r::Hydro)` instead.") GenX.min_power(gen[hydro_res[1]])
# 3. min_flow should work with old column name
@test GenX.min_flow.(gen[hydro_res]) == [0.117, 0.18, 0.402]
# 4. min_flow should be the same as min_power with old column name
@test GenX.min_flow.(gen[hydro_res]) == GenX.min_power.(gen[hydro_res])
# 5. min_flow should be using the new column name
test_hydro = GenX.Hydro(Dict(:resource => "test_hydro",
:min_flow => 10.0))
@test GenX.min_flow(test_hydro) == 10.0
@test GenX.min_power(test_hydro) == 0.0
# 6. min_flow has the priority over min_power with old column name
test_hydro = GenX.Hydro(Dict(:resource => "test_hydro",
:min_flow => 10.0,
:min_power => 5.0))
@test GenX.min_flow(test_hydro) == 10.0
@test GenX.min_power(test_hydro) == 5.0
# 7. default is zero
@test GenX.min_flow(GenX.Hydro(Dict(:resource => "test_hydro"))) == 0.0
# 8. resources that are not Hydro, Electrolyzer, or Thermal should throw a method error
vre_res = GenX.vre(gen)
@test_throws MethodError GenX.min_flow(gen[vre_res[1]])
end

function test_load_resources_data()
setup = Dict("ParameterScale" => 0,
"OperationalReserves" => 1,
Expand Down Expand Up @@ -290,6 +319,11 @@ function test_load_resources_data()
@testset "resource-specific attributes" begin
test_resource_specific_attributes(gen, dfGen, inputs)
end

# Test that min_flow deprecation works
@testset "Min power deprecation" begin
test_min_power_deprecation(gen, dfGen)
end
end

function test_load_VRE_STOR_data()
Expand Down