Skip to content

Port of PSI cost expression refactor#108

Open
acostarelli wants to merge 2 commits intomainfrom
ac/cost-expression-refactor
Open

Port of PSI cost expression refactor#108
acostarelli wants to merge 2 commits intomainfrom
ac/cost-expression-refactor

Conversation

@acostarelli
Copy link
Copy Markdown
Member

@acostarelli acostarelli requested a review from Copilot May 5, 2026 19:50
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Ports PSI’s cost-expression refactor into POM/PSI by bundling cost expression container creation, expanding thermal cost decomposition, and adding renewable curtailment-cost tracking.

Changes:

  • Replaced scattered add_expressions! calls with centralized add_cost_expressions! across device constructors.
  • Added standalone renewable CurtailmentCostExpression and objective contribution via add_curtailment_cost!.
  • Updated tests to reflect expanded expression exports and validate decomposition/nonnegativity.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
test/test_model_decision.jl Adjusts expectations for increased exported expressions and outputs.
test/test_device_thermal_generation_constructors.jl Adds decomposition checks and startup-cost attribution checks.
test/test_device_renewable_generation_constructors.jl Adds nonnegativity test for CurtailmentCostExpression.
src/static_injector_models/thermalgeneration_constructor.jl Switches to add_cost_expressions! for thermal devices.
src/static_injector_models/source_constructor.jl Switches to add_cost_expressions! for sources.
src/static_injector_models/renewablegeneration_constructor.jl Switches to add_cost_expressions! for renewables.
src/static_injector_models/renewable_generation.jl Adds curtailment cost into renewable objective.
src/static_injector_models/load_constructor.jl Switches to add_cost_expressions! for loads.
src/common_models/objective_function.jl Implements renewable curtailment cost objective terms.
src/common_models/market_bid_plumbing.jl Routes VOM proportional cost to VOMCostExpression.
src/common_models/add_to_expression.jl Refactors fuel-consumption expression building and compact formulation handling.
src/common_models/add_expressions.jl Adds add_cost_expressions! bundles and fuel/polynomial predicates.
src/PowerOperationsModels.jl Imports/exports additional cost expression types and includes new objective helpers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

# treat as no-op rather than erroring so renewables with PWL/other costs still build.
_add_curtailment_cost!(
::OptimizationContainer, ::Type{<:VariableType}, ::PSY.RenewableGen,
::PSY.OperationalCost, ::Type{<:AbstractDeviceFormulation}) = nothing
Comment on lines +2733 to +2751
for t in time_steps
sos_status = _get_sos_value(container, W, d)
if sos_status == SOSStatusVariable.NO_VARIABLE
JuMP.add_to_expression!(expression[name, t], P_min * prop_term_per_unit * dt)
elseif sos_status == SOSStatusVariable.PARAMETER
param = get_default_on_parameter(d)
bin = get_parameter(container, param, V).parameter_array[name, t]
JuMP.add_to_expression!(
expression[name, t], P_min * prop_term_per_unit * dt, bin)
elseif sos_status == SOSStatusVariable.VARIABLE
var = get_default_on_variable(d)
bin = get_variable(container, var, V)[name, t]
JuMP.add_to_expression!(
expression[name, t], P_min * prop_term_per_unit * dt, bin)
else
@assert false
end
JuMP.add_to_expression!(
expression[name, t], prop_term_per_unit * dt, variable[name, t])
Comment on lines +139 to +145
n = length(devices)
all_names = Vector{String}(undef, n)
fuel_names = sizehint!(String[], n)
has_quad_fuel = false
for (i, d) in enumerate(devices)
name = PSY.get_name(d)
all_names[i] = name
@test length(read_parameters(res; table_format = TableFormat.WIDE)) == 1
@test length(read_duals(res; table_format = TableFormat.WIDE)) == 0
@test length(read_expressions(res; table_format = TableFormat.WIDE)) == 2
@test length(read_expressions(res; table_format = TableFormat.WIDE)) == 7

@test length(readdir(IOM.export_realized_outputs(outputs1))) === 7
exported = readdir(IOM.export_realized_outputs(outputs1))
@test length(exported) >= 12
@acostarelli acostarelli requested a review from jd-lara May 5, 2026 21:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants