Skip to content

Fix renewable reactive power: FixedOutput Q = P and constant-pf sin/tan - #408

Merged
jd-lara merged 3 commits into
mainfrom
lk/renewable-reactive-power
Oct 27, 2026
Merged

jd-lara merged 3 commits into
mainfrom
lk/renewable-reactive-power

Conversation

@luke-kiernan

Copy link
Copy Markdown
Collaborator

Fixes #381.

  • FixedOutput renewables: scale the reactive parameter multiplier by tan(acos(pf)).
  • RenewableConstantPowerFactor: q = p · tan(acos(pf)), not sin.

Thermal/hydro FixedOutput have the same Q = P default but no power_factor field, so they are left for a follow-up.

🤖 Generated with Claude Code

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.

🟢 Approval recommended

The focused fixes match the reported defects and include targeted regression coverage; tests were not executed.

No open issues 🎉

What changed in this PR

Corrects renewable reactive-power calculations in AC models, addressing issue #381. Thermal and hydro behavior remains unchanged.

Changes:

  • Scales renewable FixedOutput reactive multipliers by tan(acos(pf)).
  • Corrects the constant-power-factor equation and clarifies its ratio variable.
  • Adds regression tests for both corrections at power factor 0.8.
File Description
test/​test_device_renewable_generation_constructors.jl Tests reactive multipliers and constraint coefficients.
src/​static_injector_models/​renewable_generation.jl Corrects both renewable reactive-power calculations.

Review effort: Balanced

@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Performance Results

Version Precompile Time
Main 2.649021889
This Branch 2.537325029
Version Build Time
Main-Build Time Precompile 79.838039774
Main-Build Time Postcompile 1.065620671
This Branch-Build Time Precompile 77.800950962
This Branch-Build Time Postcompile 0.980543114
Version Solve Time
Main-Solve Time Precompile 2060.804242517
Main-Solve Time Postcompile 2046.05821947
This Branch-Solve Time Precompile 1730.598133745
This Branch-Solve Time Postcompile 1702.038840577

@luke-kiernan
luke-kiernan marked this pull request as draft October 19, 2026 22:20
@luke-kiernan

luke-kiernan commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator Author

Reverted to draft momentarily while I figure out how to make all 3 of the below happen at once:

  1. When there's no user-provided reactive power time series, then we use Q = P * tan(acos(pf)).
  2. When there is a user-provided reactive power time series, we use that one.
  3. In both cases above, the power flow in the loop sees the same value as optimization problem.

edit: oh, a further oddity. If you have a reactive power time series that's attached to some devices but not all, then the ones with the time series get treatment 2 above, but the rest get Q = 0, when you'd expect them to get treatment 1. This just seems like a side effect of device model being specified per component type, though.

edit: back to ready for review. I decided just to open a stacked PR

@rodrigomha

Copy link
Copy Markdown
Contributor

Reviewed and ran it merged onto current main: the renewable, load and power-flow-in-the-loop test files all pass (1749/1749). The red CI is the FD-vs-NR tolerance failure that #412 fixed, so merging main should turn it green.

One request: guard against `power_factor == 0`.
PSY accepts `power_factor` in [0, 1], and `tan(acos(0)) ≈ 1.6e16`.
A renewable with pf = 0 would get a reactive multiplier (`FixedOutput`) or constraint coefficient (`RenewableConstantPowerFactor`) of about 1e16 times its active power, and nothing would say so.
The old `sin` version at least capped the ratio at 1.
Could both paths throw an `IS.ConflictingInputsError` at build time when pf is 0, naming the device?

@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.

See above about pf = 0

luke-kiernan and others added 3 commits October 27, 2026 10:48
The reactive time-series parameter reads the max_active_power series and
used the same max_active_power multiplier as the active parameter, so every
FixedOutput renewable injected Q = P. Scale the reactive multiplier by
Q/P = tan(acos(power_factor)). Part of #381.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A constant power factor fixes q = p * tan(acos(pf)); the constraint used
sin(acos(pf)), giving q/p = 0.6 instead of 0.75 at pf = 0.8. Rename the
local to q_to_p since it is a ratio, not a power factor. Part of #381.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
tan(acos(0)) is about 1.6e16, so a pf = 0 renewable got a huge reactive
multiplier (FixedOutput) or constraint coefficient
(RenewableConstantPowerFactor). Both now throw a ConflictingInputsError
naming the device.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@luke-kiernan
luke-kiernan force-pushed the lk/renewable-reactive-power branch from a6918e7 to f5dbee8 Compare October 27, 2026 17:05

@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.

Approving. The pf = 0 guard covers both the FixedOutput multiplier and RenewableConstantPowerFactor, with a test for each. At f5dbee8, the renewable, load and power-flow-in-the-loop test files pass locally (1751/1751), and the formatter is clean.

@codecov

codecov Bot commented Oct 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@luke-kiernan

Copy link
Copy Markdown
Collaborator Author

This is finished and good to merge from my perspective--just I don't have permissions to do so

@jd-lara
jd-lara merged commit 6b335fe into main Oct 27, 2026
8 checks passed
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.

Renewable reactive power: FixedOutput injects Q = P, and constant power factor uses sin instead of tan

4 participants