Document active-power limit constraints for thermals and loads

Open
#73 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
48/100
Issue type
Documentation
Clarity
Mostly clear
Activity status
Quiet
Tech stack
julia
Domain
documentation

Research direction

Start by reading the referenced sections of electric_loads.jl and thermal_generation.jl, especially the constraint-building methods and their named helpers. Record the existing constraint keys, meta strings, bounds, and row-counting conventions in project documentation, including the listed inconsistencies. Done means the current behavior is documented without proposing fixes.

Written by the indexing model from the issue text.

Description

documentation

Context

The active-power upper/lower-bound constraint machinery across thermal and load device families uses a mix of constraint types, meta strings, and row-counting conventions that isn't documented anywhere. This issue captures the current state on paper, as a prerequisite to deciding what's intentional design vs. accumulated technical debt.

All keys below are ConstraintKey(ConstraintType, ComponentType, meta).

Loads

InterruptiblePowerLoad with PowerLoadInterruption + forecast attached:

Key RHS Source
(ActivePowerVariableTimeSeriesLimitsConstraint, InterruptiblePowerLoad, "") p ≤ forecast_t · pmax electric_loads.jl:118-140add_parameterized_upper_bound_range_constraints
(ActivePowerVariableLimitsConstraint, InterruptiblePowerLoad, "binary") p ≤ u · pmax electric_loads.jl:142-169

Plus a JuMP variable lower bound p ≥ 0 from get_variable_lower_bound (electric_loads.jl:9). There is no ActivePowerVariableLimitsConstraint row for the nameplate — the nameplate UB is enforced via the JuMP variable's upper bound, not a constraint.

PowerLoadDispatch omits the "binary" row (no OnVariable) and otherwise looks the same.

Thermals

AbstractThermalDispatchFormulation (no commitment, no forecast):

Key RHS Source
(ActivePowerVariableLimitsConstraint, ThermalGen, "lb"/"ub") pmin ≤ p ≤ pmax via add_range_constraints! thermal_generation.jl:294-310

AbstractThermalUnitCommitment (commitment, no forecast):

Key RHS Source
(ActivePowerVariableLimitsConstraint, ThermalGen, "lb"/"ub") pmin · u ≤ p ≤ pmax · u via add_semicontinuous_range_constraints! thermal_generation.jl:377-391

AbstractThermalUnitCommitment + forecast attached — adds on top of commitment:

Key RHS Source
(ActivePowerVariableTimeSeriesLimitsConstraint, ThermalGen, "") p ≤ forecast_t · pmax thermal_generation.jl:462-484

ThermalMultiStartUnitCommitment — multiple metas under the same constraint type:

Key RHS Source
(ActivePowerVariableLimitsConstraint, ThermalMultiStart, "on") p ≤ (pmax−pmin)·u − max(pmax−startup, 0)·v thermal_generation.jl:489-567
(ActivePowerVariableLimitsConstraint, ThermalMultiStart, "off") startup/shutdown trajectory UB same method
(ActivePowerVariableLimitsConstraint, ThermalMultiStart, "lb") p ≥ 0 same method
(ActivePowerVariableLimitsConstraint, ThermalMultiStart, "ubon") via ActivePowerRangeExpressionUB thermal_generation.jl:614-681
(ActivePowerVariableLimitsConstraint, ThermalMultiStart, "uboff") same same
(ActivePowerVariableLimitsConstraint, ThermalMultiStart, "lb") (expression) expression ≥ 0 via ActivePowerRangeExpressionLB thermal_generation.jl:569-612

Observed inconsistencies

Descriptive, not prescriptive — flagging for discussion, not proposing fixes:

  1. Commitment coupling lives under different keys across device families.

    • Thermals: (ActivePowerVariableLimitsConstraint, …, "lb"/"ub") for both dispatch and UC, plus "on"/"off"/"ubon"/"uboff" for multi-start.
    • Loads: (ActivePowerVariableLimitsConstraint, …, "binary") — a meta string that exists nowhere on the thermal side.
  2. Forecast + commitment are never folded into a single row. Thermal UC with forecast produces two separate rows (p ≤ pmax·u and p ≤ forecast_t · pmax) under different constraint types. Loads do the same. ThermalMultiStartUnitCommitment does fold commitment and startup/shutdown trajectories into a single row — but not forecast.

  3. The meta-string vocabulary is ad-hoc. Thermals use "lb", "ub", "on", "off", "ubon", "uboff". Loads use "binary". Nothing enforces or documents the vocabulary; no registry of valid metas per constraint type.

  4. Lower bounds are enforced three different ways.

    • JuMP variable bound (loads; thermal dispatch via add_range_constraints!)
    • Explicit constraint row with meta "lb" (thermal multi-start)
    • Expression-based ≥ 0 under the same "lb" meta (thermal multi-start with ActivePowerRangeExpressionLB)

    The ThermalMultiStart case reuses the "lb" meta for two semantically different rows (one on the variable, one on an expression), which would collide if both code paths ran for the same device.

  5. Nameplate UB materialization is asymmetric. Thermals always create an ActivePowerVariableLimitsConstraint row. Loads push the nameplate into the JuMP variable's upper bound and only materialize a constraint row when commitment (PowerLoadInterruption) or a forecast is involved.

Dominant language
Julia
Stars
2
Forks
1
Avg merge
1d 16h
Merged PRs (30d)
26

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from Sienna-Platform/PowerOperationsModels.jl

All issues in Sienna-Platform/PowerOperationsModels.jl

Similar issues

More Julia issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.