Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
d969b85
refactor MBC/IEC for PSY static/time-series type split
luke-kiernan Apr 13, 2026
cc2f88d
add _shutdown_cost_value for LinearCurve shutdown field
luke-kiernan Apr 13, 2026
8a9b33f
refactor startup/shutdown costs: trait-based dispatch, split mock cos…
luke-kiernan Apr 13, 2026
b5595e8
format, cleanup: remove POM test utils, type and compile-time fixes
luke-kiernan Apr 13, 2026
4d1d69c
fix latent bugs surfaced by POM unit tests
luke-kiernan Apr 14, 2026
ed5e7bb
update for `TupleTimeSeries`
luke-kiernan Apr 14, 2026
0ce9382
handle TupleTimeSeries in apply_maybe_across_time_series
luke-kiernan Apr 15, 2026
7fc9465
Merge remote-tracking branch 'origin/main' into lk/mbc_iec_refactor
luke-kiernan Apr 17, 2026
ce498b6
replace isa with dispatch
luke-kiernan Apr 17, 2026
f7830af
copilot comments
luke-kiernan Apr 17, 2026
7df716e
light refactor of `powersystems_utils.jl`
luke-kiernan Apr 17, 2026
2cee375
fix NDMT typing
jd-lara Apr 20, 2026
6d1e755
fix time variant logic
jd-lara Apr 20, 2026
528215b
clean up value curve cost
jd-lara Apr 20, 2026
5b4af9b
remove PSY references
jd-lara Apr 20, 2026
8464f7f
POM testing: call on sys.data, adjust mocks. format too
luke-kiernan Apr 20, 2026
83e523b
`is_time_variant_proportional` rename, fix
luke-kiernan Apr 20, 2026
a187d24
remove special case, still fails
luke-kiernan Apr 20, 2026
6b42ecd
Merge remote-tracking branch 'origin/main' into lk/mbc_iec_refactor
jd-lara Apr 22, 2026
2f3741d
be smarted about the settings
jd-lara Apr 22, 2026
c67dddf
CoPilot code review
luke-kiernan Apr 22, 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
2 changes: 1 addition & 1 deletion .claude/claude.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ src/
file_utils.jl # File I/O utilities
logging.jl # Logging setup
indexing.jl # Index/key utilities
powersystems_utils.jl # PowerSystems integration utilities
component_utils.jl # Component filtering and unit-system conversion helpers (IS-only)
time_series_utils.jl # Time series helpers
generate_valid_formulations.jl # Formulation validation
print_pt_v2.jl / print_pt_v3.jl # Pretty-printing
Expand Down
2 changes: 0 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
Logging = "56ddb016-857b-54e1-b83d-db4d58db5568"
MathOptInterface = "b8f27783-ece8-5eb3-8dc8-9495eed66fee"
PowerNetworkMatrices = "bed98974-b02a-5e2f-9fe0-a103f5c450dd"
PowerSystems = "bcd98974-b02a-5e2f-9ee0-a103f5c450dd"
PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
Expand All @@ -41,7 +40,6 @@ LinearAlgebra = "1"
Logging = "1"
MathOptInterface = "1"
PowerNetworkMatrices = "^0.19"
PowerSystems = "5"
PrettyTables = "3.1"
Random = "^1.10"
Serialization = "1"
Expand Down
2 changes: 1 addition & 1 deletion docs/src/explanation/time_varying_objective_functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ implements:
| Validate device-specific constraints | Generic validation | Device-specific overloads (e.g., multi-start units) |
| Populate parameter containers | — | `add_parameters!` implementations |
| Read parameters during objective build | `add_pwl_term!`, `add_cost_term_variant!` | — |
| Determine if cost is time-varying | — | `is_time_variant_term` implementations |
| Determine if cost is time-varying | — | `is_time_variant_proportional` implementations |
| Extract proportional cost per step | — | `proportional_cost` implementations |

```mermaid
Expand Down
41 changes: 21 additions & 20 deletions src/InfrastructureOptimizationModels.jl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import JuMP.Containers: DenseAxisArray, SparseAxisArray
import MathOptInterface
import LinearAlgebra
import JSON3
import PowerSystems
import InfrastructureSystems
import PowerNetworkMatrices
import PowerNetworkMatrices: PTDF, VirtualPTDF, LODF, VirtualLODF
Expand Down Expand Up @@ -90,22 +89,30 @@ import InfrastructureSystems:
InvalidValue,
ConflictingInputsError

# PowerSystems imports
import PowerSystems:
# IS re-exports of generic component/time-series accessors
import InfrastructureSystems:
get_components,
get_component,
get_available_components,
get_available_component,
get_groups,
get_available_groups,
stores_time_series_in_memory,
get_base_power,
get_active_power_limits,
get_start_up,
get_shut_down,
get_must_run,
get_operation_cost
import PowerSystems: StartUpStages
stores_time_series_in_memory

# Extension-point stubs for accessors that downstream packages (e.g. POM) provide
# methods for when operating on PSY types.
function get_base_power end
function get_active_power_limits end
function get_max_active_power end
function get_ramp_limits end
function get_start_up end
function get_shut_down end
function get_must_run end
function get_operation_cost end
function get_dc_bus end
function get_bustype end
function has_service end
function set_units_base_system! end

import TimerOutputs

Expand All @@ -131,7 +138,6 @@ import PrettyTables
################################################################################
# Type Aliases

const PSY = PowerSystems
const POM = InfrastructureOptimizationModels
const IS = InfrastructureSystems
const ISOPT = InfrastructureSystems.Optimization
Expand Down Expand Up @@ -168,7 +174,6 @@ export get_power_flow_evaluation, has_subnetworks, get_subsystem
export set_subsystem!, add_dual!
export requires_all_branch_models, supports_branch_filtering, ignores_branch_filtering
export validate_network_model
Comment thread
luke-kiernan marked this conversation as resolved.
export validate_available_devices
export BranchReductionOptimizationTracker
export get_variable_dict, get_constraint_dict, get_constraint_map_by_type
export get_number_of_steps, set_number_of_steps!
Expand Down Expand Up @@ -225,7 +230,6 @@ export add_pwl_linking_constraint!
export add_pwl_normalization_constraint!
export add_pwl_sos2_constraint!
export get_pwl_cost_expression_delta
export process_market_bid_parameters!

## Outputs interfaces
export get_variable_values
Expand Down Expand Up @@ -334,13 +338,12 @@ export search_for_reduced_branch_parameter!
export search_for_reduced_branch_argument!
export get_branch_argument_parameter_axes
export get_parameter_dict
export get_device_with_time_series
export get_branch_with_time_series
# Container/variable helpers
export add_variable_container!, add_constraint_dual!
export add_to_objective_invariant_expression!, lazy_container_addition!
export get_parameter_multiplier_array, get_aux_variable, get_condition
export supports_milp, get_quadratic_cost_per_system_unit
export check_hvdc_line_limits_unidirectional, check_hvdc_line_limits_consistency
export add_sparse_pwl_interpolation_variables!
export JuMPOrFloat
Comment thread
luke-kiernan marked this conversation as resolved.
# Constraint helpers
Expand All @@ -362,7 +365,6 @@ export get_min_max_limits
export AbstractThermalDispatchFormulation, AbstractThermalUnitCommitment
# Service/misc helpers
# NOTE: get_time_series NOT exported — conflicts with IS.get_time_series. Use IOM.get_time_series.
export process_import_export_parameters!, process_market_bid_parameters!
# Extension point functions
export add_service_variables!, requires_initialization
# End bulk-added
Expand All @@ -377,7 +379,7 @@ export get_incompatible_devices
export OptimizationContainer, OperationModel, AbstractPowerFlowEvaluationModel
export ArgumentConstructStage, ModelConstructStage
export EmulationModelStore, DeviceModelForBranches
export StartUpStages, SOSStatusVariable
export SOSStatusVariable
# Parameter types
export FuelCostParameter, VariableValueParameter, FixValueParameter
# Offer curve types (parameter, variable, constraint)
Expand Down Expand Up @@ -586,7 +588,6 @@ include("objective_function/start_up_shut_down.jl") # add_{start_up, shut_down}_
# same 5 arguments: container, variable, component, cost_curve, formulation.
include("objective_function/linear_curve.jl")
include("objective_function/quadratic_curve.jl")
include("objective_function/import_export.jl")

# Offer curve types (pure type definitions, no dependencies)
include("objective_function/offer_curve_types.jl")
Expand Down Expand Up @@ -644,7 +645,7 @@ include("utils/file_utils.jl")
include("utils/logging.jl")
include("utils/dataframes_utils.jl")
include("utils/jump_utils.jl")
include("utils/powersystems_utils.jl")
include("utils/component_utils.jl")
include("utils/time_series_utils.jl")
include("utils/datetime_utils.jl")
end
2 changes: 1 addition & 1 deletion src/common_models/add_auxiliary_variable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function add_variables!(
container,
T,
D,
PSY.get_name.(devices),
IS.get_name.(devices),
time_steps,
)
return
Expand Down
30 changes: 17 additions & 13 deletions src/common_models/add_constraint_dual.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Device model
function add_constraint_dual!(
container::OptimizationContainer,
sys::PSY.System,
sys::IS.InfrastructureSystemsContainer,
model::DeviceModel{T, D},
) where {T <: PSY.Component, D <: AbstractDeviceFormulation}
) where {T <: IS.InfrastructureSystemsComponent, D <: AbstractDeviceFormulation}
if !isempty(get_duals(model))
devices = get_available_components(model, sys)
for constraint_type in get_duals(model)
Expand All @@ -16,11 +16,11 @@ end
# Network model
function add_constraint_dual!(
container::OptimizationContainer,
sys::PSY.System,
sys::IS.InfrastructureSystemsContainer,
model::NetworkModel{T},
) where {T <: AbstractPowerModel}
if !isempty(get_duals(model))
devices = get_available_components(model, PSY.ACBus, sys)
devices = get_available_components(model, IS.InfrastructureSystemsComponent, sys)
for constraint_type in get_duals(model)
assign_dual_variable!(container, constraint_type, devices, model)
end
Expand All @@ -31,9 +31,9 @@ end
# Service model
function add_constraint_dual!(
container::OptimizationContainer,
sys::PSY.System,
sys::IS.InfrastructureSystemsContainer,
model::ServiceModel{T, D},
) where {T <: PSY.Service, D <: AbstractServiceFormulation}
) where {T <: IS.InfrastructureSystemsComponent, D <: AbstractServiceFormulation}
if !isempty(get_duals(model))
service = get_available_components(model, sys)
for constraint_type in get_duals(model)
Expand All @@ -49,9 +49,9 @@ function assign_dual_variable!(
constraint_type::Type{<:ConstraintType},
service::D,
::Type{<:AbstractServiceFormulation},
) where {D <: PSY.Service}
) where {D <: IS.InfrastructureSystemsComponent}
time_steps = get_time_steps(container)
service_name = PSY.get_name(service)
service_name = IS.get_name(service)
add_dual_container!(
container,
constraint_type,
Expand All @@ -69,18 +69,20 @@ function assign_dual_variable!(
constraint_type::Type{<:ConstraintType},
devices::U,
::Type{<:AbstractDeviceFormulation},
) where {U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}} where {D <: PSY.Device}
) where {
U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}},
} where {D <: IS.InfrastructureSystemsComponent}
@assert !isempty(devices)
time_steps = get_time_steps(container)
metas = _existing_constraint_metas(container, constraint_type, D)
if isempty(metas)
device_names = PSY.get_name.(devices)
device_names = IS.get_name.(devices)
add_dual_container!(container, constraint_type, D, device_names, time_steps)
else
# Reuse the existing constraint container's row axis so the dual axis
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have tests for this somewhere (probably need to go in POM)? If not, open an issue to add them.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Issue opened: POM #93

# matches the constraint exactly. Network reductions (radial /
# degree-two) drop branches that pass the device-model filter, so the
# constraint axis is a strict subset of PSY.get_name.(devices). Sizing
# constraint axis is a strict subset of IS.get_name.(devices). Sizing
# the dual from the device list would leave the dual broadcast in
# process_duals incompatible with the constraint matrix.
for meta in metas
Expand Down Expand Up @@ -121,14 +123,16 @@ function assign_dual_variable!(
constraint_type::Type{<:ConstraintType},
devices::U,
::NetworkModel{<:AbstractPowerModel},
) where {U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}} where {D <: PSY.ACBus}
) where {
U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}},
} where {D <: IS.InfrastructureSystemsComponent}
@assert !isempty(devices)
time_steps = get_time_steps(container)
add_dual_container!(
container,
constraint_type,
D,
PSY.get_name.(devices),
IS.get_name.(devices),
time_steps,
)
return
Expand Down
6 changes: 5 additions & 1 deletion src/common_models/add_param_container.jl
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,11 @@ function add_param_container!(
axs...;
sparse = false,
meta = CONTAINER_KEY_EMPTY_META,
) where {T <: EventParameter, U <: IS.InfrastructureSystemsComponent, V <: PSY.Contingency}
) where {
T <: EventParameter,
U <: IS.InfrastructureSystemsComponent,
V <: IS.InfrastructureSystemsComponent,
}
param_key = ParameterKey(T, U, meta)
attributes = EventParametersAttributes(V)
return add_param_container_shared_axes!(
Expand Down
12 changes: 6 additions & 6 deletions src/common_models/add_variable.jl
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,10 @@ function add_service_variables!(
::Type{F},
) where {
T <: VariableType,
U <: PSY.Service,
Comment thread
luke-kiernan marked this conversation as resolved.
U <: IS.InfrastructureSystemsComponent,
V <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}},
F <: AbstractServiceFormulation,
} where {D <: PSY.Component}
} where {D <: IS.InfrastructureSystemsComponent}
@assert !isempty(contributing_devices)
time_steps = get_time_steps(container)

Expand All @@ -100,16 +100,16 @@ function add_service_variables!(
container,
T,
U,
PSY.get_name(service),
[PSY.get_name(d) for d in contributing_devices],
IS.get_name(service),
[IS.get_name(d) for d in contributing_devices],
time_steps,
)

for t in time_steps, d in contributing_devices
name = PSY.get_name(d)
name = IS.get_name(d)
variable[name, t] = JuMP.@variable(
get_jump_model(container),
base_name = "$(T)_$(U)_$(PSY.get_name(service))_{$(name), $(t)}",
base_name = "$(T)_$(U)_$(IS.get_name(service))_{$(name), $(t)}",
binary = binary
)

Expand Down
2 changes: 1 addition & 1 deletion src/common_models/constraint_helpers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ function add_updown_constraints_containers!(
::Type{V},
names,
time_steps,
) where {T <: ConstraintType, V <: PSY.Component}
) where {T <: ConstraintType, V <: IS.InfrastructureSystemsComponent}
return (
up = add_constraints_container!(container, T, V, names, time_steps; meta = "up"),
down = add_constraints_container!(
Expand Down
12 changes: 8 additions & 4 deletions src/common_models/duration_constraints.jl
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ function device_duration_retrospective!(
initial_duration::Matrix{InitialCondition},
::Type{C},
::Type{T},
) where {C <: ConstraintType, T <: PSY.Component}
) where {C <: ConstraintType, T <: IS.InfrastructureSystemsComponent}
time_steps = get_time_steps(container)

varon = get_variable(container, OnVariable, T)
Expand Down Expand Up @@ -145,7 +145,11 @@ function device_duration_look_ahead!(
::Type{C_up},
::Type{C_dn},
::Type{T},
) where {C_up <: ConstraintType, C_dn <: ConstraintType, T <: PSY.Component}
) where {
C_up <: ConstraintType,
C_dn <: ConstraintType,
T <: IS.InfrastructureSystemsComponent,
}
time_steps = get_time_steps(container)
varon = get_variable(container, OnVariable, T)
varstart = get_variable(container, StartVariable, T)
Expand Down Expand Up @@ -243,7 +247,7 @@ function device_duration_parameters!(
initial_duration::Matrix{InitialCondition},
::Type{C},
::Type{T},
) where {C <: ConstraintType, T <: PSY.Component}
) where {C <: ConstraintType, T <: IS.InfrastructureSystemsComponent}
time_steps = get_time_steps(container)

varon = get_variable(container, OnVariable, T)
Expand Down Expand Up @@ -365,7 +369,7 @@ function device_duration_compact_retrospective!(
initial_duration::Matrix{InitialCondition},
::Type{C},
::Type{T},
) where {C <: ConstraintType, T <: PSY.Component}
) where {C <: ConstraintType, T <: IS.InfrastructureSystemsComponent}
time_steps = get_time_steps(container)

varon = get_variable(container, OnVariable, T)
Expand Down
6 changes: 3 additions & 3 deletions src/common_models/get_time_series.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# NOTE not included currently.
function _get_time_series(
container::OptimizationContainer,
component::PSY.Component,
component::IS.InfrastructureSystemsComponent,
attributes::TimeSeriesAttributes{T};
interval::Dates.Millisecond = UNSET_INTERVAL,
) where {T <: IS.TimeSeriesData}
Expand All @@ -20,7 +20,7 @@ function get_time_series(
::Type{P},
meta = CONTAINER_KEY_EMPTY_META;
interval::Dates.Millisecond = UNSET_INTERVAL,
) where {T <: PSY.Component, P <: TimeSeriesParameter}
) where {T <: IS.InfrastructureSystemsComponent, P <: TimeSeriesParameter}
parameter_container = get_parameter(container, P, T, meta)
return _get_time_series(
container,
Expand All @@ -34,7 +34,7 @@ end
# refactor is done.
function get_time_series(
container::OptimizationContainer,
component::PSY.Component,
component::IS.InfrastructureSystemsComponent,
forecast_name::String;
interval::Dates.Millisecond = UNSET_INTERVAL,
)
Expand Down
Loading
Loading