G-1 reserves; use IOM.ComponentPairKey; EnumX changes - #321
acostarelli wants to merge 22 commits into
Conversation
…straint and slacks on flow
… slacks keys need to be reconsidered I think
…of reserves code; enumx
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Unresolved critical dependency, test, reserve-keying, and G-1 monitoring issues block approval.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 6
Open (9)
Include device type in participation constraint keys · New Fix inverted modeled branch type condition · New Use a portable remote path for the test dependency · New Restore the compatible PowerFlows source pin · New Restore the PowerFlows test import · New Handle absent requirement containers in the test · New Restore the HVDCDCControlConstraint public export · New Restore system snapshot persistence in system_to_file · New Validate monitored branches against the filtered catalog · New
What changed in this PR
Ports G-1 security-constrained reserve modeling, migrates reserve indexing to IOM.ComponentPairKey, and updates related models and tests.
Changes:
- Adds post-contingency reserve deployment, balance, flow, and slack modeling.
- Updates reserve construction, aggregation, offers, and device integrations.
- Updates EnumX handling, dependencies, output persistence, and regression coverage.
| File | Changes | Final review findings |
|---|---|---|
test/test_static_injection_security_constrained_models.jl |
Adds G-1 regression coverage. | Critical (1): No-requirement test checks an absent container incorrectly. |
test/test_services_constructor.jl |
Updates reserve-container assertions. | — |
test/test_model_decision.jl |
Adapts reserve output discovery. | — |
test/test_device_reserve_offers.jl |
Reads typed reserve awards. | — |
test/Project.toml |
Updates test dependencies and sources. | Critical (3): Contributor-specific absolute path. Critical (3): Removed compatible remote source while PowerFlows tests remain enabled. |
test/includes.jl |
Changes test imports. | Critical (3): PFS import is disabled while dependent tests remain enabled. |
src/static_injector_models/thermal_generation.jl |
Updates offline reserve lookup. | — |
src/static_injector_models/hydro_generation.jl |
Updates reserve variable keys. | — |
src/services_models/services_constructor.jl |
Constructs security-constrained service models. | — |
src/services_models/security_constrained_injectors.jl |
Implements G-1 reserve modeling. | Critical (1): Modeled branch types are skipped due to an inverted condition. Moderate (2): Validation ignores the per-device filter_function. |
src/services_models/reserves.jl |
Migrates reserve aggregation and costs. | Critical (1): Participation constraints can collide without device-type keys. |
src/services_models/reserve_offers.jl |
Supports device-type offer keys. | — |
src/services_models/reserve_group.jl |
Aggregates pair-keyed reserve variables. | — |
src/PowerOperationsModels.jl |
Registers and exports G-1 APIs. | Moderate (3): Removes the existing HVDCDCControlConstraint export. |
src/operation/template_validation.jl |
Reorganizes outage validation. | — |
src/operation/decision_model.jl |
Changes system output persistence. | Moderate (3): Comments out the PSY.to_file persistence call. |
src/hybrid_system_models/hybrid_systems.jl |
Updates hybrid reserve keys. | — |
src/energy_storage_models/storage_models.jl |
Updates storage reserve keys. | — |
src/core/variables.jl |
Adds G-1 variables. | — |
src/core/formulations.jl |
Adds security-constrained reserve formulations. | Nit (1): Documentation inaccurately describes service attachment validation. |
src/core/expressions.jl |
Adds post-contingency expressions. | — |
src/core/constraints.jl |
Adds G-1 constraints. | Nit (1): Exported constraint retains an incomplete docstring. |
src/common_models/converter_control.jl |
Updates EnumX type signatures. | — |
src/common_models/add_to_expression.jl |
Updates reserve expression keys. | — |
Project.toml |
Updates package sources and dependencies. | Critical (3): Contributor-specific absolute path prevents clean checkout and CI instantiation. |
ext/PowerFlowsExt/pf_headroom.jl |
Updates EnumX bus typing. | — |
.claude/pom_port_plan.md |
Removes the porting plan. | — |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| export RealizedShiftedLoadMinimumBoundConstraint | ||
| export NonAnticipativityConstraint | ||
| export HVDCDCControlConstraint | ||
| export PostContingencyGenerationBalanceConstraint |
| flows are built only on modeled components, so monitored components must be a subset of the | ||
| modeled ones. | ||
| """ | ||
| function _check_security_constrained_reserve_monitors( |
There was a problem hiding this comment.
This feels like this should be in template validation.
There was a problem hiding this comment.
Also I'm not sure if we need a whole check for this. We can either error or warn when building the deviation variables.
| end | ||
|
|
||
| # Outaged generators whose power the model can remove; the rest are skipped with a warning. | ||
| function _outaged_generators( |
There was a problem hiding this comment.
Why is this helper per one outage, and the other one is per all the outages?
| ) | ||
| outage::PSY.Outage, | ||
| ) | ||
| outaged = _PER_TYPE() |
There was a problem hiding this comment.
I'm considering dropping this const alias.
| return monitored_components | ||
| end | ||
|
|
||
| # Parallel circuits share one reduced entry, so each entry is constrained once. |
| end | ||
|
|
||
| # Every outage gets a balance row per network region. Modeled interchanges carry a deviation | ||
| # variable per outage, balanced across areas; monitored interchanges (a subset of the modeled |
There was a problem hiding this comment.
I think the subset comment is unnecessary.
| ) | ||
| for devices in values(contributing_devices) | ||
| # Ramp limits bind spinning reserves only. | ||
| _is_ramp_formulation(F) && R <: PSY.Reserve && |
| ), | ||
| ) | ||
|
|
||
| _valid_component_type(::PSY.ACTransmission, ::NetworkModel{<:AbstractPTDFNetworkModel}) = |
There was a problem hiding this comment.
Maybe better name like _valid_monitored_component
| ::NetworkModel{AreaBalanceNetworkModel}, | ||
| ) | ||
| if !has_container_key(container, FlowActivePowerVariable, PSY.AreaInterchange) | ||
| @warn "An AreaBalanceNetworkModel with security-constrained reserves needs PSY.AreaInterchange(s) and DeviceModel{PSY.AreaInterchange} for reserve deployment to cross area boundaries. Otherwise, each area must cover its own outages." _group = |
There was a problem hiding this comment.
Don't love how this is worded
| struct BThetaBranchFlow <: ExpressionType end | ||
| struct PostContingencyNodalActivePowerDeployment <: PostContingencyExpressions end | ||
|
|
||
| """ |
There was a problem hiding this comment.
I think we can combine this with the area one and just do PostContingencyLocationalDeployment
| end | ||
|
|
||
| _post_contingency_flow_expression(::NetworkModel{<:AbstractPTDFNetworkModel}) = | ||
| PostContingencyBranchFlow |
There was a problem hiding this comment.
Same thought here, we can combine these and do PostContingencyBranchFlow or some more generic name than Branch. And both PTDF and Area will use the same.
| return outaged | ||
| end | ||
|
|
||
| function _monitored_components( |
There was a problem hiding this comment.
Still not checking for filtered?
|
@acostarelli we should close this and reopen with just the G-1 code |


Requires Sienna-Platform/InfrastructureOptimizationModels.jl#171