Skip to content
Merged
Show file tree
Hide file tree
Changes from 53 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
0bf1ff5
Bilinear hydro formulation and IOM/PSY API updates
Apr 29, 2026
001b82a
Merge branch 'main' into ac/hydro-bilinear
acostarelli Apr 29, 2026
4ad672f
claude initial
Apr 30, 2026
b36ad3c
fix time-series parameter accessing; fix onparameter cost adding
May 4, 2026
e0d67dc
simplify constructor
May 5, 2026
e2e7871
formatting
May 5, 2026
8d93d17
address reviews: add type untyped arguments; support reservation, reg…
May 7, 2026
a3d2c6b
format
May 7, 2026
6b827d4
refactor: unify two-sided hybrid+storage methods via trait dispatch
May 8, 2026
59c994b
refactor: defer hybrid thermal range constraints to IOM helper
May 8, 2026
5dea6aa
Revert "refactor: defer hybrid thermal range constraints to IOM helper"
May 8, 2026
379d8c5
docs: rename Bounds → Domain in HybridDispatchWithReserves docstring
May 8, 2026
353ca8e
refactor: replace isa-on-service with multiple-dispatch helpers
May 8, 2026
0d43888
restore tests
May 8, 2026
9dd7ef6
refactor: parametric abstract types collapse paired hybrid reserve fa…
May 11, 2026
a00df13
formatting
May 11, 2026
2343c8e
rename abstract types
May 11, 2026
b962d2b
Merge remote-tracking branch 'origin/main' into ac/hybrid
May 11, 2026
8a83bce
formatting
May 11, 2026
f559b20
Merge remote-tracking branch 'origin/main' into ac/hydro-bilinear
May 12, 2026
9bc4add
Address review comments on bilinear hydro test
May 13, 2026
a73d189
Rename HydroTurbineBin2BilinearDispatch to MILP and expose bilinear_a…
May 13, 2026
57bc7ae
switch HydroTurbineMILPBilinearDispatch from n_segments to tolerance
May 28, 2026
147ec06
Replace bilinear attribute config with POM config structs
May 30, 2026
b938cbd
Merge remote-tracking branch 'origin/main' into ac/hydro-milp-rename
Jun 1, 2026
8363d0b
Simplify bilinear _iom_config bridge against updated IOM contract
Jun 1, 2026
f03f49f
Generalize bilinear configs to x×y and validate tolerance
Jun 2, 2026
929fa0c
refactor: remove const aliases, use parametric types directly
Jun 3, 2026
1d84d0f
reuse PSY.reservedirection
Jun 3, 2026
de5735d
Return to attribute-based bilinear config, deriving epigraph depth fr…
Jun 5, 2026
b4e1a6c
Merge remote-tracking branch 'origin/main' into ac/hydro-milp-rename
Jun 8, 2026
0414f81
update source branches
Jun 8, 2026
14dbbfd
removed excessive comments and tests
Jun 8, 2026
297007c
remove storage_of helper
Jun 8, 2026
e8f7333
Merge remote-tracking branch 'origin/main' into ac/hybrid
Jun 8, 2026
ccca499
Make converter loss approximations attribute-driven
Jun 8, 2026
475769b
Add relative tolerance to bilinear approximation API
Jun 8, 2026
5ebe8f6
Merge NLP+MILP bilinear formulations into single attribute-driven types
Jun 8, 2026
3919d47
Address June 8 review: centralize bilinear attrs, tighten tolerance, …
Jun 8, 2026
9d930d6
two-layer -> one-layer helper with extra noop for ambiguity
Jun 8, 2026
d954775
remove excessive comments and tests
Jun 8, 2026
1f3d6f7
copilot review
Jun 8, 2026
da98c62
fix target for approximation test
Jun 9, 2026
1b1aa08
Fix vacuous HVDC MILP/NLP agreement test
Jun 9, 2026
43465c2
remove bad test
Jun 9, 2026
44f9cf4
fix a few more reserve traits
Jun 9, 2026
4ea83cb
Merge remote-tracking branch 'origin/ac/hydro-milp-rename' into ac/hy…
Jun 9, 2026
964a665
formatting
Jun 9, 2026
4fded2c
tests run faster; use units in getters
Jun 9, 2026
46fdac2
Merge remote-tracking branch 'origin/main' into ac/hybrid
Jun 9, 2026
8aa359a
Address PR #104 June-9 review: storage reserve bug, storage-less hybr…
Jun 9, 2026
cc7aca5
Fix hybrid energy target: restore surplus/shortage slacks (soft equal…
Jun 9, 2026
3f9fa11
formatting
Jun 9, 2026
88e44b7
Apply suggestions from code review
acostarelli Jun 9, 2026
09e4a34
Merge branch 'main' into ac/hybrid
jd-lara Jun 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ PowerFlows = "94fada2c-fd9a-4e89-8d82-81405f5cb4f6"

[sources]
InfrastructureSystems = {rev = "IS4", url = "https://github.com/Sienna-Platform/InfrastructureSystems.jl"}
PowerSystems = {rev = "psy6", url = "https://github.com/Sienna-Platform/PowerSystems.jl"}
# TODO: Move to main once this branch is merged
PowerSystems = {rev = "ac/hybridsystem-strip-units", url = "https://github.com/Sienna-Platform/PowerSystems.jl"}
InfrastructureOptimizationModels = {rev = "main", url = "https://github.com/Sienna-Platform/InfrastructureOptimizationModels.jl"}
PowerNetworkMatrices = {rev = "psy6", url = "https://github.com/Sienna-Platform/PowerNetworkMatrices.jl"}

Expand Down
47 changes: 39 additions & 8 deletions src/PowerOperationsModels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ include("core/problem_types.jl")
include("core/interfaces.jl")
include("core/default_interface_methods.jl")
include("core/physical_constant_definitions.jl")
include("core/reserve_traits.jl")
include("core/variables.jl")
include("core/expressions.jl")
include("core/constraints.jl")
Expand Down Expand Up @@ -303,6 +304,10 @@ include("services_models/reserve_group.jl")
include("services_models/transmission_interface.jl")
include("services_models/services_constructor.jl")

# Hybrid System Models (after services_models since they share reserve infrastructure)
include("hybrid_system_models/hybrid_systems.jl")
include("hybrid_system_models/hybridsystem_constructor.jl")

# Two-Terminal HVDC Models
# NOTE: AC_branches.jl and branch_constructor.jl in twoterminal_hvdc_models/ are
# identical copies of the files in ac_transmission_models/ — do NOT include them.
Expand Down Expand Up @@ -653,6 +658,7 @@ export StorageEnergyOutput
export EnergyBalanceConstraint
export StateofChargeLimitsConstraint
export StateofChargeTargetConstraint
export HybridEnergyTargetConstraint
export StorageCyclingCharge
export StorageCyclingDischarge
export StorageRegularizationConstraintCharge
Expand All @@ -667,19 +673,44 @@ export ReserveChargeConstraint

# expressions
export TotalReserveOffering
export ReserveAssignmentBalanceUpDischarge
export ReserveAssignmentBalanceUpCharge
export ReserveAssignmentBalanceDownDischarge
export ReserveAssignmentBalanceDownCharge
export ReserveDeploymentBalanceUpDischarge
export ReserveDeploymentBalanceUpCharge
export ReserveDeploymentBalanceDownDischarge
export ReserveDeploymentBalanceDownCharge

Comment thread
acostarelli marked this conversation as resolved.
# parameters
export EnergyLimitParameter
export EnergyTargetParameter

######## Hybrid System Formulations ########
export AbstractHybridFormulation
export AbstractHybridFormulationWithReserves
export HybridDispatchWithReserves

# Reserve / constraint marker traits used to parametrize hybrid + storage families.
export ReserveScale, UnscaledReserve, DeployedReserve
export ReserveSide, DischargeSide, ChargeSide

# variables
export HybridEnergyShortageVariable
export HybridEnergySurplusVariable
export HybridRenewableActivePower
export HybridRenewableReserveVariable
export HybridStorageReservation
export HybridThermalActivePower
export HybridThermalReserveVariable

# expressions

# constraints
export HybridEnergyAssetBalanceConstraint
export HybridRenewableActivePowerLimitConstraint
export HybridRenewableReserveLimitConstraint
export HybridReserveAssignmentConstraint
export HybridReserveBalanceConstraint
export HybridStorageBalanceConstraint
export HybridThermalReserveLimitConstraint

# parameters
export HybridElectricLoadTimeSeriesParameter
export HybridRenewableActivePowerTimeSeriesParameter

#################################################################################
# Exports - Constraint Types (defined in core/constraints.jl)
#################################################################################
Expand Down
81 changes: 81 additions & 0 deletions src/core/constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1064,3 +1064,84 @@ The specified constraints are formulated as:
```
"""
struct ShiftDownActivePowerVariableLimitsConstraint <: PowerVariableLimitsConstraint end

#################################################################################
# Hybrid System Constraints
#################################################################################

"""
Couples the hybrid PCC reserve variables (out + in) to the system-level
`ActivePowerReserveVariable` of each service the hybrid participates in.
"""
struct HybridReserveAssignmentConstraint <: ConstraintType end

"""
Couples the hybrid PCC reserve variables (out + in) to the sum of per-subcomponent reserve
allocations (thermal + renewable + charging + discharging).
"""
struct HybridReserveBalanceConstraint <: ConstraintType end

"""
Equates the hybrid's PCC active-power injection to the sum of internal subcomponent
flows (thermal + renewable + storage discharge - storage charge - load) net of served
reserves.
"""
struct HybridEnergyAssetBalanceConstraint <: ConstraintType end

"""
Status link between a hybrid PCC active-power variable and the reservation variable.
Parametric on [`ReserveSide`](@ref).`.
"""
Comment thread
acostarelli marked this conversation as resolved.
struct HybridStatusOnConstraint{Sd <: ReserveSide} <: ConstraintType end

"""
Bound between thermal subcomponent power and its commitment status (no-reserves case).
Parametric on `BoundDirection` (from IOM).
"""
struct HybridThermalOnVariableConstraint{B <: IOM.BoundDirection} <: ConstraintType end

"Range constraint on thermal subcomponent power including up/down reserves."
struct HybridThermalReserveLimitConstraint <: ConstraintType end

"Upper bound on renewable subcomponent power from the time-series forecast."
struct HybridRenewableActivePowerLimitConstraint <: ConstraintType end

"Range constraint on renewable subcomponent power including up/down reserves."
struct HybridRenewableReserveLimitConstraint <: ConstraintType end

"Energy balance for the storage subcomponent of a hybrid system, including reserve deployment."
struct HybridStorageBalanceConstraint <: ConstraintType end

"""
Mutually-exclusive charge/discharge limit for the hybrid storage subcomponent
(no-reserves case). Parametric on [`ReserveSide`](@ref).
"""
struct HybridStorageStatusOnConstraint{Sd <: ReserveSide} <: ConstraintType end

"""
Charge- or discharge-side power limit for the hybrid storage subcomponent including
reserve carve-outs. Parametric on [`ReserveSide`](@ref).
"""
struct HybridStorageReservePowerLimitConstraint{Sd <: ReserveSide} <: ConstraintType end

"""
Bounds the absolute charge- or discharge-power step change between consecutive time
steps, penalizing oscillation. Active only when the hybrid `\"regularization\"`
attribute is set. Parametric on [`ReserveSide`](@ref).
"""
struct RegularizationConstraint{Sd <: ReserveSide} <: ConstraintType end

"""
End-of-period energy target for the storage subcomponent of a hybrid system.
Used when the attribute `energy_target = true`.

Like the storage [`StateofChargeTargetConstraint`](@ref), this is a soft equality with
non-negative surplus ([`HybridEnergySurplusVariable`](@ref), energy above target) and
shortage ([`HybridEnergyShortageVariable`](@ref), energy below target) slacks penalized
in the objective:

```math
e^{st}_{T} - e^{st+} + e^{st-} = E^{st}_{T}.
```
"""
struct HybridEnergyTargetConstraint <: ConstraintType end
53 changes: 38 additions & 15 deletions src/core/expressions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -78,25 +78,46 @@ of the energy balance for the system in medium term planning
struct EnergyBalanceExpression <: ExpressionType end

#################################################################################
# Energy Storage Expressions
# Energy Storage / Hybrid Reserve Aggregation Expressions
#
# A single parametric family covers both the hybrid PCC boundary aggregation
# (HybridPCCReserveExpression) and the storage-subcomponent balance aggregation
# (StorageReserveBalanceExpression). The three axes are:
# D <: ReserveDirection : Up | Down
# S <: ReserveScale : UnscaledReserve (multiplier 1.0)
# | DeployedReserve (multiplier = get_deployed_fraction(s))
# Sd <: ReserveSide : DischargeSide (PCC "Out" / storage "Discharge")
# | ChargeSide (PCC "In" / storage "Charge")
#################################################################################

"""
Per-device, per-service aggregation of the reserve quantity offered by a storage device
(or the storage subcomponent of a hybrid system). One container is created per service
participated in, and the per-component reserve variables (charging + discharging) are
summed into it. Consumed by [`HybridReserveBalanceConstraint`](@ref) and used as the
right-hand side of the system-level reserve balance.
"""
struct TotalReserveOffering <: ExpressionType end

abstract type StorageReserveDischargeExpression <: ExpressionType end
abstract type StorageReserveChargeExpression <: ExpressionType end
abstract type ReserveAggregationExpression{
D <: PSY.ReserveDirection,
S <: ReserveScale,
Sd <: ReserveSide,
} <: ExpressionType end

# Used for the Power Limits constraints
struct ReserveAssignmentBalanceUpDischarge <: StorageReserveDischargeExpression end
struct ReserveAssignmentBalanceUpCharge <: StorageReserveChargeExpression end
struct ReserveAssignmentBalanceDownDischarge <: StorageReserveDischargeExpression end
struct ReserveAssignmentBalanceDownCharge <: StorageReserveChargeExpression end
"""
Hybrid-boundary aggregation of reserve quantities offered through the discharge (out) and
charge (in) sides of a `PSY.HybridSystem`.
"""
struct HybridPCCReserveExpression{D, S, Sd} <:
ReserveAggregationExpression{D, S, Sd} end

# Used for the SoC estimates
struct ReserveDeploymentBalanceUpDischarge <: StorageReserveDischargeExpression end
struct ReserveDeploymentBalanceUpCharge <: StorageReserveChargeExpression end
struct ReserveDeploymentBalanceDownDischarge <: StorageReserveDischargeExpression end
struct ReserveDeploymentBalanceDownCharge <: StorageReserveChargeExpression end
"""
Aggregation of reserve variables allocated to the storage subcomponent of a hybrid system
(or a standalone storage device).
"""
struct StorageReserveBalanceExpression{D, S, Sd} <:
ReserveAggregationExpression{D, S, Sd} end
Comment thread
acostarelli marked this conversation as resolved.

# Method extensions for output writing
should_write_resulting_value(::Type{InterfaceTotalFlow}) = true
Expand All @@ -108,8 +129,10 @@ should_write_resulting_value(::Type{HydroServedReserveDownExpression}) = true
should_write_resulting_value(::Type{TotalHydroFlowRateReservoirOutgoing}) = true
should_write_resulting_value(::Type{TotalHydroFlowRateTurbineOutgoing}) = true

should_write_resulting_value(::Type{StorageReserveDischargeExpression}) = true
should_write_resulting_value(::Type{StorageReserveChargeExpression}) = true
should_write_resulting_value(::Type{<:StorageReserveBalanceExpression}) = true
should_write_resulting_value(
::Type{HybridPCCReserveExpression{D, DeployedReserve, Sd}},
) where {D <: PSY.ReserveDirection, Sd <: ReserveSide} = true

# Method extensions for unit conversion
convert_output_to_natural_units(::Type{InterfaceTotalFlow}) = true
Expand Down
Loading
Loading