Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ DocStringExtensions = "~0.8, ~0.9"
InfrastructureSystems = "3"
InteractiveUtils = "1.11.0"
JuMP = "^1.28"
PowerSystems = "5.10"
PowerFlows = "0.21"
PowerNetworkMatrices = "^0.24"
PowerSystems = "5.3"
PrettyTables = "3"
ProgressMeter = "1.11.0"
TimerOutputs = "~0.5"
Expand Down
3 changes: 3 additions & 0 deletions src/common_models/market_bid_plumbing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,9 @@ IOM.get_base_power(c::PSY.Component) = PSY.get_base_power(c, PSY.NU)
IOM.get_operation_cost(c::PSY.Component) = PSY.get_operation_cost(c)
IOM.get_must_run(c::PSY.Component) = PSY.get_must_run(c)
IOM.get_active_power_limits(c::PSY.Component) = PSY.get_active_power_limits(c, PSY.SU)
# `RenewableGen` has no `active_power_limits` field: return (0.0, max_active_power)
IOM.get_active_power_limits(c::PSY.RenewableGen) =
(min = 0.0, max = PSY.get_max_active_power(c, PSY.SU))
IOM.get_max_active_power(c::PSY.Component) = PSY.get_max_active_power(c, PSY.SU)
IOM.get_ramp_limits(c::PSY.Component) = PSY.get_ramp_limits(c, PSY.SU)
IOM.get_start_up(op_cost) = PSY.get_start_up(op_cost)
Expand Down
32 changes: 32 additions & 0 deletions test/test_device_renewable_generation_constructors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,35 @@ end
IOM.ModelBuildStatus.BUILT
@test solve!(model) == IOM.RunStatus.SUCCESSFULLY_FINALIZED
end

@testset "Renewable with quadratic variable cost builds objective (issue #9)" begin
# Regression test: a RenewableDispatch with a quadratic cost curve used to call
# `PSY.get_active_power_limits`, but renewables only have a max active power field,
# not active power limits.
c_sys5_re = PSB.build_system(PSITestSystems, "c_sys5_re")

quad_re = get_component(RenewableDispatch, c_sys5_re, "WindBusA")
base_cost = get_operation_cost(quad_re)
# Renewable ActivePowerVariable costs use OBJECTIVE_FUNCTION_NEGATIVE, so the negated
# objective term `-cost(p)` is convex (and free of the non-monotonicity warning) when
# the raw curve is concave, i.e. negative coefficients.
set_operation_cost!(
quad_re,
RenewableGenerationCost(;
variable = CostCurve(QuadraticCurve(-2.0, -1.0, 0.0)),
curtailment_cost = base_cost.curtailment_cost,
fixed = base_cost.fixed,
),
)

device_model = DeviceModel(RenewableDispatch, RenewableFullDispatch)
model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_re)
# Before the fix this threw `ArgumentError: get_active_power_limits not implemented
# for RenewableDispatch`; now it constructs a quadratic objective.
mock_construct_device!(model, device_model)
psi_checkobjfun_test(model, GQEVF)

# Direct check of the bridge that the issue is about.
@test IOM.get_active_power_limits(quad_re) ==
(min = 0.0, max = PSY.get_max_active_power(quad_re, PSY.SU))
end
Loading