Conversation
|
Performance Results This branch |
|
Closes #76 |
There was a problem hiding this comment.
Pull request overview
This PR extends InfrastructureOptimizationModels.jl to support per-device bounds for quadratic/bilinear approximation formulations and adds explicit forecast interval handling (including auto-transforming static time series into forecasts when building a DecisionModel).
Changes:
- Refactors quadratic/bilinear approximation builders to accept
Vector{MinMax}bounds (per component name) instead of global scalar min/max bounds. - Adds
Settings.interval, interval-aware time-series cache keys, and interval-aware time-series lookup/plumbing (incl. network reductions and model store params). - Introduces automatic static→deterministic time-series transformation when a model is built with a specified
(horizon, interval)and only static series exist.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/utils/powersystems_utils.jl | Adds interval/resolution conversion helpers and auto-transform + interval inspection utilities. |
| src/utils/jump_utils.jl | Adds get_hinted_aff_expr and a new long-format DataFrame conversion overload for 3D arrays with integer axes. |
| src/quadratic_approximations/solver_sos2.jl | Switches SOS2 quadratic approximation to per-name bounds and pre-sized variable containers. |
| src/quadratic_approximations/manual_sos2.jl | Switches manual SOS2 quadratic approximation to per-name bounds and pre-sized containers. |
| src/quadratic_approximations/sawtooth.jl | Switches sawtooth quadratic approximation to per-name bounds. |
| src/quadratic_approximations/epigraph.jl | Switches epigraph relaxation to per-name bounds. |
| src/quadratic_approximations/pwmcc_cuts.jl | Switches PWMCC cuts to per-name bounds and pre-sized containers. |
| src/quadratic_approximations/common.jl | Updates normalized-variable helper to use per-name bounds. |
| src/quadratic_approximations/no_approx.jl | Updates no-op quadratic approximation signature to accept per-name bounds. |
| src/quadratic_approximations/nmdt_common.jl | Updates NMDT shared utilities to carry per-name bounds through normalization/product assembly. |
| src/quadratic_approximations/nmdt.jl | Updates NMDT/DNMDT quadratic approximation interfaces to accept per-name bounds. |
| src/bilinear_approximations/bin2.jl | Updates Bin2 bilinear approximation to use per-name bounds (including auxiliary variable bounds). |
| src/bilinear_approximations/hybs.jl | Updates HybS bilinear approximation to use per-name bounds (including z bounds). |
| src/bilinear_approximations/mccormick.jl | Adds per-name bounds overload for McCormick envelope and updates reformulated cuts interface. |
| src/bilinear_approximations/nmdt.jl | Updates NMDT/DNMDT bilinear approximation interfaces to accept per-name bounds. |
| src/bilinear_approximations/no_approx.jl | Updates no-op bilinear approximation signature to accept per-name bounds. |
| src/core/settings.jl | Adds interval to Settings plus get_interval/set_interval!. |
| src/core/definitions.jl | Adds UNSET_INTERVAL and PTDF_ZERO_TOL. |
| src/operation/decision_model.jl | Adds interval keyword to constructor, auto-transform hook, and interval validation/selection logic. |
| src/operation/time_series_interface.jl | Adds interval/resolution-aware cache keys and forwarding of interval/resolution to time-series APIs. |
| src/core/optimization_container.jl | Extends initial time-series lookup to accept interval/resolution keywords. |
| src/common_models/get_time_series.jl | Threads interval through helper time-series getters. |
| src/core/network_reductions.jl | Adds interval-aware time-series UUID selection for reduced branch parameter axes. |
| src/operation/decision_model_store.jl | Adds write_output! overload for 3D arrays with integer axes. |
| src/common_models/add_constraint_dual.jl | Aligns dual containers’ row axes with existing constraint containers (handles reduced networks). |
| src/operation/model_numerical_analysis_utils.jl | Splits constraint coefficient vs RHS bound updates (new default fallbacks). |
| src/InfrastructureOptimizationModels.jl | Exports get_interval. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| for name in names, t in time_steps | ||
| for (i, name) in enumerate(names), t in time_steps | ||
| b = bounds[i] |
There was a problem hiding this comment.
lx is computed from per-device bounds and is later used as a divisor in the linking constraint. If any entry in bounds has min == max (or max < min), this will introduce division-by-zero/invalid scaling and break the model. Add an explicit per-name check (e.g. assert b.max > b.min) before computing/using lx, similar to the guards in epigraph.jl/sawtooth.jl.
| b = bounds[i] | |
| b = bounds[i] | |
| @assert b.max > b.min "Invalid bounds for $(name): expected max > min, got min=$(b.min), max=$(b.max)" |
| model_interval = get_interval(settings) | ||
| available_intervals = get_forecast_intervals(sys) | ||
| if model_interval == UNSET_INTERVAL && length(available_intervals) > 1 | ||
| throw( | ||
| IS.ConflictingInputsError( | ||
| "The system contains multiple forecast intervals $(available_intervals). " * | ||
| "The `interval` keyword argument must be provided to the DecisionModel constructor " * | ||
| "to select which interval to use.", | ||
| ), | ||
| ) | ||
| elseif model_interval != UNSET_INTERVAL && !isempty(available_intervals) | ||
| if model_interval ∉ available_intervals | ||
| throw( | ||
| IS.ConflictingInputsError( | ||
| "Interval $(Dates.canonicalize(model_interval)) is not available in the system data. " * | ||
| "Available forecast intervals: $(available_intervals)", | ||
| ), | ||
| ) | ||
| end | ||
| end | ||
| interval_kwarg = | ||
| model_interval == UNSET_INTERVAL ? (;) : (; interval = model_interval) |
There was a problem hiding this comment.
The new interval-selection logic (multiple forecast intervals error, validating a user-specified interval, and passing interval into get_forecast_horizon) introduces new behavior that isn’t currently covered by the test suite. Please add tests that (1) build a system with multiple forecast intervals and assert the constructor errors unless interval is provided, and (2) verify that a provided interval is used (and rejected when unavailable).
| function to_outputs_dataframe( | ||
| array::DenseAxisArray{ | ||
| Float64, | ||
| 3, | ||
| <:Tuple{Vector{String}, UnitRange{Int}, UnitRange{Int}}, | ||
| }, | ||
| ::Nothing, | ||
| ::Val{TableFormat.LONG}, | ||
| ) | ||
| num_rows = length(array.data) | ||
| time_col = Vector{Int}(undef, num_rows) | ||
| name_col = Vector{String}(undef, num_rows) | ||
| name2_col = Vector{Int}(undef, num_rows) | ||
| vals = Vector{Float64}(undef, num_rows) | ||
|
|
||
| row_index = 1 | ||
| for name in axes(array, 1) | ||
| for name2 in axes(array, 2) | ||
| for time_index in axes(array, 3) | ||
| time_col[row_index] = time_index | ||
| name_col[row_index] = name | ||
| name2_col[row_index] = name2 | ||
| vals[row_index] = array[name, name2, time_index] | ||
| row_index += 1 | ||
| end | ||
| end | ||
| end | ||
|
|
||
| return DataFrame( | ||
| :time_index => time_col, | ||
| :name => name_col, | ||
| :name2 => name2_col, | ||
| :value => vals, | ||
| ) | ||
| end |
There was a problem hiding this comment.
This adds a new to_outputs_dataframe overload for 3D DenseAxisArray with axes (Vector{String}, UnitRange{Int}, UnitRange{Int}) when timestamps are nothing, but test/test_jump_utils.jl only covers the (Vector{String}, Vector{String}, UnitRange) 3D case. Add a unit test for this new axis shape to ensure the long-format output has the expected row count and column values/order.
|
@acostarelli Address the comments from copilot and test again before merging. We can discuss when I come back from PTO |
… for unsupported constraint in numerical analysis; added output handling methods for different variable arrays
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
8d8764b to
d188616
Compare
| return | ||
| end | ||
|
|
||
| function write_output!( |
There was a problem hiding this comment.
Seems mildly unrelated to the topic of the PR. Needed to fix some test?
There was a problem hiding this comment.
I wrote this in conjunction with Sienna-Platform/PowerOperationsModels.jl#87 , and I was getting an error trying to read the output in testing that formulation.
|
|
||
| """ | ||
| _assemble_product!(container, C, names, time_steps, terms, dz_var, x_disc, y_disc, meta; result_type) | ||
| _assemble_product!(container, C, names, time_steps, terms, dz_var, xh_norm, yh_norm, x_bounds, y_bounds, meta; result_type) |
There was a problem hiding this comment.
Maybe it's obvious, but I'm not seeing wheter these extra arguments came from, what changed to make them needed.
There was a problem hiding this comment.
The docstring was outdated from the method signature: the NMDTDiscretization structs used to store the min and max as well.
Thanks for opening a PR to InfrastructureOptimizationModels.jl, please take note of the following when making a PR:
Check the contributor guidelines