Skip to content

Use curtailment in renewable cost - #1614

Merged
jd-lara merged 3 commits into
mainfrom
ac/renewable-curtailment-cost-multiplier
Jun 7, 2026
Merged

Use curtailment in renewable cost#1614
jd-lara merged 3 commits into
mainfrom
ac/renewable-curtailment-cost-multiplier

Conversation

@acostarelli

Copy link
Copy Markdown
Member

Closes #1154

Renewable variable cost previously got a -1.0 objective multiplier so that
RenewableGenerationCost.variable doubled as both a VOM cost and a dispatch
incentive. Now that RenewableGenerationCost has a separate curtailment_cost
field, each field can carry its true sign: variable contributes +VOM*p
(real cost), and curtailment_cost contributes -curtailment_cost*p (a reward
for dispatching). CurtailmentCostExpression keeps reporting the positive
dollar value of curtailed energy.

Fixes #1154.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Updates renewable generation cost handling so dispatch is no longer incentivized via a negative variable cost; instead, the incentive is applied via the curtailment_cost field, aligning the implementation with Issue #1154.

Changes:

  • Switch renewable dispatch objective multiplier for ActivePowerVariable from negative to positive (so variable cost contributes with +1.0).
  • Add an explicit negative objective contribution derived from curtailment_cost while continuing to record CurtailmentCostExpression for reporting.
  • Update RenewableGen formulation docs to describe the new (C_var - C_curt) * p net objective effect and clarify curtailment reporting.

Reviewed changes

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

File Description
src/devices_models/devices/renewable_generation.jl Flips renewable dispatch objective multiplier sign to make variable cost positive.
src/devices_models/devices/common/objective_function/linear_curve.jl Adds the curtailment incentive term to the objective for linear curtailment costs.
docs/src/formulation_library/RenewableGen.md Updates formulation documentation to reflect the new objective terms and reporting behavior.
Comments suppressed due to low confidence (2)

src/devices_models/devices/common/objective_function/linear_curve.jl:273

  • Same as above: prefer using a named sign constant (e.g., OBJECTIVE_FUNCTION_NEGATIVE) instead of hard-coding the negation for the curtailment objective term, to keep sign semantics consistent across objective-function implementations.
        _add_proportional_term!(
            container,
            T(),
            component,
            -proportional_term_per_unit * dt,
            t,
        )

docs/src/formulation_library/RenewableGen.md:138

  • Same wording issue here: “otherwise it curtails” is too absolute because dispatch can still occur due to feasibility requirements or relative costs. Consider describing the marginal incentive/disincentive of (C^{re,var} - C^{re,curt}) without implying it alone determines dispatch.
The net contribution is ``(C^\text{re,var} - C^\text{re,curt}) \cdot p_t^\text{re}``: when ``C^\text{re,curt} > C^\text{re,var}`` the optimizer dispatches the unit, otherwise it curtails. `CurtailmentCostExpression` reports the per-device dollar value of curtailed energy ``C^\text{re,curt} \cdot (p^\text{re,max}_t - p_t^\text{re})`` and is not propagated to `ProductionCostExpression`.

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

Comment thread docs/src/formulation_library/RenewableGen.md Outdated
Comment on lines +211 to +217
_add_proportional_term!(
container,
T(),
component,
-proportional_term_per_unit * dt,
t,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@acostarelli This is correct. We should add a test that verifies that this works. I would make the suggested test for copilot

@github-actions

github-actions Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor

Performance Results

Version Precompile Time
Main 3.992943377
This Branch 3.899655993
Version Build Time
Main-Build Time Precompile 128.413285026
Main-Build Time Postcompile 1.459567394
This Branch-Build Time Precompile 123.846578441
This Branch-Build Time Postcompile 1.463089046
Version Build Time
Main-Solve Time Precompile 948.662846691
Main-Solve Time Postcompile 898.082947393
This Branch-Solve Time Precompile 439.969345336
This Branch-Solve Time Postcompile 393.724942267

@rodrigomha rodrigomha left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@acostarelli Minor changes here, but this is almost ready for review.

Here is suggestion from copilot to handle the test:

Proposed test (to add to test/test_device_renewable_generation_constructors.jl)

Add a testset after the nonnegativity test that:

  1. Builds a RenewableFullDispatch model using a system with both variable and curtailment_cost set on RenewableGenerationCost
  2. Solves the model
  3. Asserts dispatch changes (or objective value changes) relative to a baseline with curtailment_cost = 0
  4. Optionally asserts the sign of the objective coefficient on ActivePowerVariable is negative when curtailment_cost > variable_cost

Anthony Costarelli and others added 2 commits May 28, 2026 17:03
- Use OBJECTIVE_FUNCTION_NEGATIVE constant for the curtailment
  objective coefficient instead of an inline unary `-`.
- Rephrase RenewableFullDispatch and RenewableConstantPowerFactor
  docstrings to describe the marginal incentive and note that system
  constraints (load balance, reserves) may still require dispatch.
- Add a regression test that sets `curtailment_cost > variable` and
  asserts both that renewable dispatch increases vs. a baseline with
  `curtailment_cost = 0` and that the JuMP coefficient on
  ActivePowerVariable is negative.
- Fix `_add_curtailment_cost!` to derive `offer_max` from the
  ActivePowerTimeSeriesParameter (falling back to
  `get_max_active_power` for renewables without a time series). The
  previous `_get_pwl_data` call required offer curves that
  RenewableGenerationCost does not provide, so the curtailment-cost
  incentive crashed at build time for any non-zero `curtailment_cost`.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

Comment on lines +195 to +205
param_array =
get_parameter_array(
container,
ActivePowerTimeSeriesParameter(),
PSY.RenewableDispatch,
)
param_multiplier = get_parameter_multiplier_array(
container,
ActivePowerTimeSeriesParameter(),
PSY.RenewableDispatch,
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is fine I believe. We want to fail if the user does not give timeseries to renewables anyways

Comment on lines +266 to +273
param_array =
get_parameter_array(container, ActivePowerTimeSeriesParameter(), PSY.RenewableGen)
param_multiplier = get_parameter_multiplier_array(
container,
ActivePowerTimeSeriesParameter(),
PSY.RenewableGen,
)
has_ts_param = name in axes(param_array)[1]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm doubting myself here. @acostarelli can you check in a test what happen if only 1 renewable (of two or more) has timeseries and what happen if no renewable has timeseries. This could be a bug.

@jd-lara
jd-lara self-requested a review June 7, 2026 21:06
@jd-lara
jd-lara merged commit 8ec4e15 into main Jun 7, 2026
11 checks passed
@jd-lara
jd-lara deleted the ac/renewable-curtailment-cost-multiplier branch July 30, 2026 04:40
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.

Update Renewable Generation Costs Formulation

4 participants