Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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: 3 additions & 0 deletions src/InfrastructureOptimizationModels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,9 @@ export ReservationVariable
export PiecewiseLinearCostVariable
export RateofChangeConstraintSlackUp, RateofChangeConstraintSlackDown
export DCVoltage
# Flow-direction trait for variable types
export FlowSign, FlowInjection, FlowWithdrawal, FlowUndirected
export flow_sign, multiplier_from_sign
# Abstract types needed by POM for type hierarchy
export SparseVariableType, InterpolationVariableType, BinaryInterpolationVariableType

Expand Down
1 change: 0 additions & 1 deletion src/common_models/rateofchange_constraints.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# NOTE: not included currently.
function _get_minutes_per_period(container::OptimizationContainer)
resolution = get_resolution(container)
if resolution > Dates.Minute(1)
Expand Down
32 changes: 32 additions & 0 deletions src/core/standard_variables_expressions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,38 @@ struct RateofChangeConstraintSlackDown <: VariableType end
# HVDC Variables (used in add_pwl_methods)
struct DCVoltage <: VariableType end

#################################################################################
# Flow direction trait
#
# Encodes the sign with which a variable contributes to a power-balance
# expression. Replaces scattered `get_variable_multiplier(...) = ±1.0` overrides
# whose only signal is the variable type itself. Device-driven sign overrides
# (e.g. anything on `PSY.ElectricLoad`) still live in POM as more-specific
# dispatches.
#################################################################################

# Holy-traits style: `flow_sign` returns a *type*, and `multiplier_from_sign`
# dispatches on `::Type{<:FlowSign}`. Both layers resolve at compile time so the
# numeric multiplier folds away at every call site.
abstract type FlowSign end
struct FlowInjection <: FlowSign end
struct FlowWithdrawal <: FlowSign end
struct FlowUndirected <: FlowSign end

# Default: no directional meaning attached to the variable type.
flow_sign(::Type{<:VariableType}) = FlowUndirected

multiplier_from_sign(::Type{FlowInjection}) = 1.0
multiplier_from_sign(::Type{FlowWithdrawal}) = -1.0
# Variables without flow semantics (OnVariable, StartVariable, ...) keep the
# legacy 1.0 default so callers that don't care about sign still work.
multiplier_from_sign(::Type{FlowUndirected}) = 1.0

# Standard variable types defined here:
flow_sign(::Type{ActivePowerVariable}) = FlowInjection
flow_sign(::Type{ActivePowerInVariable}) = FlowWithdrawal
flow_sign(::Type{ActivePowerOutVariable}) = FlowInjection

#################################################################################
# Standard Expression Types
# These are the base expression types for aggregating terms
Expand Down
1 change: 1 addition & 0 deletions test/InfrastructureOptimizationModelsTests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ function run_tests()
# TODO service_model.jl
include(joinpath(TEST_DIR, "test_settings.jl"))
# standard_variables_expressions.jl: low complexity
include(joinpath(TEST_DIR, "test_flow_sign.jl"))
# time_series_parameter_types.jl: low complexity

# --- objective_function/ subfolder ---
Expand Down
2 changes: 0 additions & 2 deletions test/Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ DataFramesMeta = "1313f7d8-7da2-5740-9ea0-a2ca25f37964"
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b"
InfrastructureOptimizationModels = "bed98974-b02a-5e2f-9ee0-a103f5c45069"
InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1"
Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9"
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
Expand All @@ -30,7 +29,6 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
UnoSolver = "1baa60ac-02f7-4b39-a7a8-2f4f58486b05"

[sources]
InfrastructureOptimizationModels = {path = ".."}
InfrastructureSystems = {rev = "IS4", url = "https://github.com/Sienna-Platform/InfrastructureSystems.jl"}

[compat]
Expand Down
28 changes: 28 additions & 0 deletions test/test_flow_sign.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
@testset "FlowSign trait" begin
@testset "multiplier_from_sign maps to expected ±1.0" begin
@test IOM.multiplier_from_sign(IOM.FlowInjection) == 1.0
@test IOM.multiplier_from_sign(IOM.FlowWithdrawal) == -1.0
@test IOM.multiplier_from_sign(IOM.FlowUndirected) == 1.0
end

@testset "flow_sign defaults to FlowUndirected" begin
# Any VariableType without an explicit override falls back to FlowUndirected.
# OnVariable / StartVariable / etc. have no flow semantics by design.
@test IOM.flow_sign(OnVariable) === IOM.FlowUndirected
@test IOM.flow_sign(StartVariable) === IOM.FlowUndirected
@test IOM.flow_sign(StopVariable) === IOM.FlowUndirected
end

@testset "Standard active-power variables carry the correct sign" begin
@test IOM.flow_sign(ActivePowerVariable) === IOM.FlowInjection
@test IOM.flow_sign(ActivePowerInVariable) === IOM.FlowWithdrawal
@test IOM.flow_sign(ActivePowerOutVariable) === IOM.FlowInjection
end

@testset "Roundtrip: multiplier_from_sign ∘ flow_sign" begin
@test IOM.multiplier_from_sign(IOM.flow_sign(ActivePowerVariable)) == 1.0
@test IOM.multiplier_from_sign(IOM.flow_sign(ActivePowerInVariable)) == -1.0
@test IOM.multiplier_from_sign(IOM.flow_sign(ActivePowerOutVariable)) == 1.0
@test IOM.multiplier_from_sign(IOM.flow_sign(OnVariable)) == 1.0
end
end
Loading