Sienna-Platform / Sienna-Platform/PowerOperationsModels.jl
Post-contingency rating time series is only honored for the outaged branch type
@acostarelli is already working on this.
Since Sep 16, 2026.
- Dominant language
- Julia
- Stars
- 2
- Forks
- 1
- Avg merge
- 1d 16h
- Merged PRs (30d)
- 26
Description
Summary
A PostContingencyBranchRatingTimeSeriesParameter is honored only when the monitored
branch's own type is modeled with an AbstractSecurityConstrainedStaticBranch formulation
and that type is itself outaged. In every other configuration the series is silently
ignored and the post-contingency limit falls back to the static rating_b.
The same branch can get both behaviors in one model: forecast-driven under outages claimed
by its own SC model, static under outages claimed by a different type's SC model.
Background: how outage claiming works
SecurityConstrainedStaticBranch on type D means outages attached to D-type components
are considered — claiming is by the outaged type
(_assign_outage_to_sc_models!: D in attached_types || continue).
The claiming model then receives the outage's entire monitored breakdown, filtered only
by "is this type modeled in the template at all"
(_monitored_components_by_modeled_type: comp_type in modeled_types, where
modeled_types = get_component_types(template) — not restricted to SC-modeled types).
So post-contingency constraints are built for monitored components of any modeled branch
type, and are stored under the claiming SC model's container key with the monitored
component's name on the axis.
Verified on c_sys14, lines outaged, everything monitored, transformers modeled
StaticBranch:
outages on the Line SC DeviceModel:
08d27fd2 -> "Line" => [Line1…Line16], "TwoWindingTransformer" => [Trans1…Trans4]
names in (PostContingencyFlowRateConstraint, Line, "ub"):
[Line1…Line16, Trans1, Trans2, Trans3, Trans4]
The problem
add_constraints! for PostContingencyFlowRateConstraint chooses between a
forecast-driven RHS and the static one via:
has_pc_rating = haskey(
get_time_series_names(device_model), # the CLAIMING SC model
PostContingencyBranchRatingTimeSeriesParameter,
)
…
if has_pc_rating && _has_post_contingency_rate(container, entry_type, name)
param, multiplier = _post_contingency_rate_columns(container, entry_type, name)
# RHS = param[t] * multiplier[t]
else
limits = _emergency_flow_limits(rep) # static rating_b
Two independent mismatches:
- The gate reads the claiming SC model's
time_series_names, not the monitored
component's model. A series declared on the monitored branch's ownDeviceModel
cannot switch on the parameterized branch for outages claimed by another type. - The container is only ever populated for the claiming model's own component type.
_add_post_contingency_branch_rating_parameter!uses
_monitored_component_names(device_model, T)over
get_available_components(device_model, sys), both of which are typeT= the SC
model's own type. The lookup, however, is keyed byentry_type = rep.component_type,
the monitored type. When those differ,_has_post_contingency_ratereturnsfalse.
Observed behavior
Series on a non-SC model — silently ignored. Transformers monitored under line
outages, modeled StaticBranch, series declared on the transformer model:
validate_template: accepted
build: BUILT
PC rating param container keyed by TwoWindingTransformer? true # created…
distinct Trans1 PC RHS values = 1 -> [24.0] == rating_b # …never consumed
The parameter container is built (by the PTDF StaticBranch constructor), so the failure
is not a missing container — it is mismatch (1): the Line SC model never declared the
series, so the gate is false.
Same branch, two behaviors. Transformers modeled SC and outaged, series on their own
model, lines also SC and outaged:
Trans1 under V=TwoWindingTransformer: outages=[6e0f8b2f, f70ecb23] RHS ∈ [22.8 … 24.0] (forecast)
Trans1 under V=Line: outages=[65136116] RHS = 24.0 (static)
Not duplicate rows — a partition by outage. Trans1's post-contingency limit follows the
forecast under transformer outages and ignores it under line outages.
Why it went unnoticed
PostContingencyBranchRatingTimeSeriesParameter had no test coverage anywhere before
3f67b44. That commit added the first one, covering only the aligned case (the series on
the SC model whose own type is outaged and monitored), which is the one path that works.
Suggested direction
Make the parameterized RHS depend on the monitored component rather than on which model
claimed the outage:
- Gate on the monitored component's
DeviceModeldeclaring the series, not the
claiming SC model's. - Populate the parameter container per monitored type, so
_has_post_contingency_rate(container, entry_type, name)can succeed when
entry_type != V. - Decide and document the intended semantics for a monitored branch whose own type is not
SC-modeled: honor the series, or reject the template. Today it is accepted and ignored.
Note this changes constraint values in configurations that currently build cleanly, so it
wants a deliberate decision rather than a drive-by fix.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.