Redistribute operation models#104
Conversation
IOM is meant to be a domain-neutral optimization-modeling library. This
removes the power-flavoured problem-type chain (DecisionProblem,
EmulationProblem, DefaultDecisionProblem, DefaultEmulationProblem,
GenericOpProblem, GenericEmulationProblem) and the five Simulation*
placeholder types that were stubs for PowerSimulations.jl.
In their place IOM gains a single abstract type:
abstract type AbstractOptimizationProblem end
DecisionModel and EmulationModel are re-parameterized over it, retaining
their phantom {M} parameter so POM-side dispatch on concrete problem tags
keeps working. IOM-side methods (get_problem_type, get_current_time,
init_model_store_params!, OptimizationProblemOutputs constructors,
error-stub validate_template) are re-rooted on the new abstract.
validate_time_series! becomes an extension-point stub (function declaration
with no methods); POM provides concrete methods on its own problem-type
chain. Outer constructors that call finalize_template! and the
EmulationModel update_parameters!/update_model!/update_parameter_values!
chain move to POM, where they belong.
Base.show methods for the removed Simulation* placeholders are deleted
from print_pt_v3.jl; the ProblemOutputsTypes union is collapsed to
OptimizationProblemOutputs.
Verified: 1144/1144 unit tests pass, plus 10/10 Aqua quality checks.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The EmulationModel struct previously carried an explicit inner constructor
that called finalize_template! — a POM-side function. That left
power-flavoured construction logic in IOM, inconsistent with how
DecisionModel handled it (no inner constructor; all construction logic in
outer methods that moved to POM in the prior commit).
Drop the inner constructor, leaving the auto-generated default
EmulationModel{M}(name, template, sys, internal, simulation_info, store,
ext) constructor. POM's Settings-taking outer constructor will do the
finalize_template!/OptimizationContainer/validate_time_series! work and
call the auto-default to construct the model.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
OperationModel was IOM's abstract supertype for DecisionModel and
EmulationModel. The "Operation" prefix carried unnecessary power-domain
flavor for what is a fully generic wrapper-level abstraction in IOM —
it describes "any optimization-model wrapper" with no domain commitment.
Rename it to AbstractOptimizationModel:
- Follows the Julia Abstract* convention (consistent with the
AbstractOptimizationProblem introduced in the prior commit).
- Removes the residual "Operation" naming from IOM.
- Reads correctly: DecisionModel/EmulationModel are concrete
optimization models, and their supertype names that role generically.
All 14 affected IOM files updated (struct supertypes, method dispatches
on the abstract type, module export). 1144/1144 unit tests pass plus
10/10 Aqua checks.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The Settings-taking, kwargs, and type-first constructors for DecisionModel
and EmulationModel are not power-specific — their bodies use only IOM
types and IOM-declared extension points (finalize_template! and
validate_time_series!). The only thing tying them to POM in the prior
commit was the `where {M <: AbstractPowerDecisionProblem}` constraint.
Move all six generic constructors (3 for DecisionModel, 3 for
EmulationModel) back to IOM, parameterized on
`<: AbstractOptimizationProblem`. The construction path is now:
1. User calls DecisionModel{MyProblem}(template, sys; horizon, ...)
2. IOM kwargs constructor builds Settings, delegates to Settings-taking
3. IOM Settings-taking constructor finalizes the template, builds the
OptimizationContainer, calls validate_time_series!
4. finalize_template! and validate_time_series! dispatch to whichever
domain library (POM, hypothetical GasOperationsModels, etc.) has
supplied methods for the concrete template/model types.
POM keeps only:
- The default-tag convenience constructor that picks
GenericPowerDecisionProblem/GenericPowerEmulationProblem
- The bare-system error stub for DefaultPowerDecisionProblem
- All the build/solve/run/reset dispatches on AbstractPower* types
- validate_template and validate_time_series! method implementations
Net effect: future domain libraries get the construction path for free
by defining their template type, implementing finalize_template! and
validate_time_series! for it, and optionally a default-tag convenience.
IOM unit tests: 1144/1144 pass, plus 10/10 Aqua checks.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
| solver/model settings, builds a `Settings`, and delegates to the | ||
| settings-taking constructor. | ||
| """ | ||
| function DecisionModel{M}( |
There was a problem hiding this comment.
@jd-lara What do you think about keeping the constructors here?
|
Performance Results This branch |
There was a problem hiding this comment.
Pull request overview
This PR refactors the operation-model type hierarchy to better separate domain-specific optimization problems from the core InfrastructureOptimizationModels (IOM) infrastructure, and updates related interfaces/printing/output writing to dispatch on the new abstractions.
Changes:
- Replace
OperationModel/DecisionProblem/EmulationProblemusage withAbstractOptimizationModel/AbstractOptimizationProblemacross the operation layer. - Remove simulation-related placeholder types/printing from IOM and narrow printing support to optimization outputs/models.
- Adjust stores/output-writing and debugging/numerical-analysis utilities to dispatch on the new abstract model type.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| test/test_utils/run_simulation.jl | Removes a test utility that built/executed a 2-step simulation. |
| src/utils/print_pt_v3.jl | Updates show dispatch to new model abstractions; removes simulation-related printing. |
| src/operation/store_common.jl | Updates output-writing dispatch from OperationModel to AbstractOptimizationModel. |
| src/operation/optimization_model_interface.jl | Renames the shared model interface file and updates dispatch signatures accordingly. |
| src/operation/optimization_debugging.jl | Updates debugging helpers to accept AbstractOptimizationModel. |
| src/operation/model_numerical_analysis_utils.jl | Updates numerical-bounds utilities to accept AbstractOptimizationModel. |
| src/operation/initial_conditions_update_in_memory_store.jl | Updates IC-update dispatch to accept AbstractOptimizationModel. |
| src/operation/emulation_model.jl | Refactors EmulationModel to parameterize on AbstractOptimizationProblem and adjusts constructors/docs. |
| src/operation/decision_model.jl | Refactors DecisionModel to parameterize on AbstractOptimizationProblem and adjusts constructors/docs. |
| src/InfrastructureOptimizationModels.jl | Updates exports/includes to reflect the new optimization-model interface naming and types. |
| src/core/optimization_problem_outputs.jl | Updates docs to reference the renamed model abstraction; minor doc cleanup. |
| src/core/operation_model_abstract_types.jl | Replaces legacy abstract types with AbstractOptimizationProblem / AbstractOptimizationModel. |
| .claude/claude.md | Updates internal file listing to reflect the new interface filename. |
Comments suppressed due to low confidence (1)
src/operation/optimization_model_interface.jl:193
get_simulation_info(model, val) = model.simulation_info = valis a setter but is named like a getter (and lacks a!). This is confusing and easy to misuse, and it also overloadsget_simulation_infowith different arity for unrelated semantics. Rename toset_simulation_info!(model, val)(and optionally keep a deprecated alias if needed).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| Dict{String, Any}(), | ||
| ) | ||
| validate_time_series!(model) | ||
| return model |
There was a problem hiding this comment.
Let's make it a no-op and maybe write a @warn
| """ | ||
| Build the optimization problem of type M with the specific system and template | ||
|
|
||
| # Arguments | ||
| DecisionModel(::Type{M}, template, sys, jump_model=nothing; kwargs...) | ||
| where {M <: AbstractOptimizationProblem} | ||
|
|
||
| - `::Type{M} where M<:DecisionProblem`: The abstract operation model type | ||
| - `template::AbstractProblemTemplate`: The model reference made up of transmission, devices, branches, and services. | ||
| - `sys::IS.InfrastructureSystemsContainer`: the system created using Power Systems | ||
| - `jump_model::Union{Nothing, JuMP.Model}` = nothing: Enables passing a custom JuMP model. Use with care. | ||
|
|
||
| # Example | ||
|
|
||
| ```julia | ||
| template = ProblemTemplate(CopperPlatePowerModel, devices, branches, services) | ||
| problem = DecisionModel(MyOpProblemType, template, system, optimizer) | ||
| ``` | ||
| Type-first dispatch variant. | ||
| """ | ||
| function DecisionModel( | ||
| ::Type{M}, | ||
| template::AbstractProblemTemplate, | ||
| sys::IS.InfrastructureSystemsContainer, | ||
| jump_model::Union{Nothing, JuMP.Model} = nothing; | ||
| kwargs..., | ||
| ) where {M <: DecisionProblem} | ||
| ) where {M <: AbstractOptimizationProblem} | ||
| return DecisionModel{M}(template, sys, jump_model; kwargs...) | ||
| end |
| EmulationModelStore(), | ||
| Dict{String, Any}(), | ||
| ) | ||
| validate_time_series!(model) |
| """ | ||
| Build the optimization problem of type M with the specific system and template | ||
|
|
||
| # Arguments | ||
| EmulationModel(::Type{M}, template, sys, jump_model=nothing; kwargs...) | ||
| where {M <: AbstractOptimizationProblem} | ||
|
|
||
| - `::Type{M} where M<:EmulationProblem`: The abstract Emulation model type | ||
| - `template::AbstractProblemTemplate`: The model reference made up of transmission, devices, | ||
| branches, and services. | ||
| - `sys::IS.InfrastructureSystemsContainer`: the system created using Power Systems | ||
| - `jump_model::Union{Nothing, JuMP.Model}`: Enables passing a custom JuMP model. Use with care | ||
|
|
||
| # Example | ||
|
|
||
| ```julia | ||
| template = ProblemTemplate(CopperPlatePowerModel, devices, branches, services) | ||
| problem = EmulationModel(MyEmProblemType, template, system, optimizer) | ||
| ``` | ||
| Type-first dispatch variant. | ||
| """ | ||
| function EmulationModel( | ||
| ::Type{M}, | ||
| template::AbstractProblemTemplate, | ||
| sys::IS.InfrastructureSystemsContainer, | ||
| jump_model::Union{Nothing, JuMP.Model} = nothing; | ||
| kwargs..., | ||
| ) where {M <: EmulationProblem} | ||
| return EmulationModel{M}(template, sys, jump_model; kwargs...) | ||
| end | ||
|
|
||
| function EmulationModel( | ||
| template::AbstractProblemTemplate, | ||
| sys::IS.InfrastructureSystemsContainer, | ||
| jump_model::Union{Nothing, JuMP.Model} = nothing; | ||
| kwargs..., | ||
| ) | ||
| return EmulationModel{GenericEmulationProblem}(template, sys, jump_model; kwargs...) | ||
| end | ||
|
|
||
| """ | ||
| Builds an empty emulation model. This constructor is used for the implementation of custom | ||
| emulation models that do not require a template. | ||
|
|
||
| # Arguments | ||
|
|
||
| - `::Type{M} where M<:EmulationProblem`: The abstract operation model type | ||
| - `sys::IS.InfrastructureSystemsContainer`: the system created using Power Systems | ||
| - `jump_model::Union{Nothing, JuMP.Model}` = nothing: Enables passing a custom JuMP model. Use with care. | ||
|
|
||
| # Example | ||
|
|
||
| ```julia | ||
| problem = EmulationModel(system, optimizer) | ||
| ``` | ||
| """ | ||
| function EmulationModel{M}( | ||
| sys::IS.InfrastructureSystemsContainer, | ||
| jump_model::Union{Nothing, JuMP.Model} = nothing; | ||
| kwargs..., | ||
| ) where {M <: EmulationProblem} | ||
| ) where {M <: AbstractOptimizationProblem} | ||
| return EmulationModel{M}(template, sys, jump_model; kwargs...) | ||
| end |
| It is recommended that `directory` be the directory that contains a serialized | ||
| OperationModel. That will allow automatic deserialization of the PowerSystems.System. | ||
| AbstractOptimizationModel. That will allow automatic deserialization of the PowerSystems.System. | ||
| The `OptimizationProblemOutputs` instance can be deserialized with `OptimizationProblemOutputs(directory)`. | ||
| """ |
| - `res::OptimizationProblemOutputs`: Outputs | ||
| - `directory::AbstractString` : target directory | ||
| - `format = "CSV"` : can be "csv" or "json |
| """ | ||
| Abstract type for Decision Model and Emulation Model. OperationModel structs are parameterized with DecisionProblem or Emulation Problem structs | ||
| """ | ||
| abstract type OperationModel end | ||
|
|
||
| #TODO: Document the required interfaces for custom types | ||
| """ | ||
| Abstract type for Decision Problems | ||
| Abstract type for any optimization problem. Concrete subtypes are provided by | ||
| downstream domain libraries (e.g. PowerOperationsModels). `DecisionModel{M}` and | ||
| `EmulationModel{M}` are parameterized over this type so any optimization problem | ||
| can be wrapped without IOM knowing its domain. | ||
|
|
||
| # Example | ||
|
|
||
| import InfrastructureOptimizationModels | ||
| const POM = InfrastructureOptimizationModels | ||
| struct MyCustomProblem <: POM.DecisionProblem | ||
| const IOM = InfrastructureOptimizationModels | ||
| struct MyCustomProblem <: IOM.AbstractOptimizationProblem end | ||
| """ | ||
| abstract type DecisionProblem end | ||
| abstract type AbstractOptimizationProblem end | ||
|
|
||
| """ | ||
| Abstract type for Emulation Problems | ||
|
|
||
| # Example | ||
|
|
||
| import InfrastructureOptimizationModels | ||
| const POM = InfrastructureOptimizationModels | ||
| struct MyCustomEmulator <: POM.EmulationProblem | ||
| Abstract supertype for `DecisionModel` and `EmulationModel`. Concrete subtypes | ||
| are parameterized with an `AbstractOptimizationProblem` subtype. | ||
| """ | ||
| abstract type EmulationProblem end | ||
|
|
||
| ################################################################################# | ||
| # Simulation Models Container | ||
| # Holds references to models in a simulation | ||
| # Used for display/printing purposes | ||
| struct SimulationModels | ||
| decision_models::Vector{<:OperationModel} | ||
| emulation_model::Union{Nothing, OperationModel} | ||
| end | ||
|
|
||
| function SimulationModels(; | ||
| decision_models, | ||
| emulation_model::Union{Nothing, OperationModel} = nothing, | ||
| ) | ||
| return SimulationModels(decision_models, emulation_model) | ||
| end | ||
|
|
||
| ################################################################################# | ||
| # Simulation Sequence | ||
| # Holds the execution sequence information for a simulation | ||
| # This is a placeholder struct - concrete implementation in PowerSimulations | ||
| struct SimulationSequence | ||
| executions_by_model::Dict | ||
| horizons::Dict | ||
| intervals::Dict | ||
| SimulationSequence() = new(Dict(), Dict(), Dict()) | ||
| end | ||
|
|
||
| # Placeholder accessor function for simulation sequence | ||
| get_step_resolution(::SimulationSequence) = Dates.Hour(1) | ||
|
|
||
| ################################################################################# | ||
| # Simulation Type | ||
| # Abstract type for simulation objects | ||
| # Concrete implementation should be in PowerSimulations | ||
| abstract type Simulation end | ||
|
|
||
| ################################################################################# | ||
| # Simulation Outputs Type | ||
| # Abstract type for simulation outputs | ||
| # Concrete implementation should be in PowerSimulations | ||
| abstract type SimulationOutputs end | ||
|
|
||
| ################################################################################# | ||
| # Simulation Problem Outputs Type | ||
| # Abstract type for individual problem outputs within a simulation | ||
| # Concrete implementation should be in PowerSimulations | ||
| abstract type SimulationProblemOutputs end | ||
| abstract type AbstractOptimizationModel end |
There was a problem hiding this comment.
No. OperationModels are a POM thing.
| @@ -500,10 +504,7 @@ export RunStatus | |||
| export SimulationBuildStatus | |||
|
|
|||
| # Problem Types | |||
| export DecisionProblem | |||
| export EmulationProblem | |||
| export DefaultDecisionProblem | |||
| export DefaultEmulationProblem | |||
| export AbstractOptimizationProblem | |||
|
|
|||
No description provided.