Infrasys System Workflows
The optional sdom.infrasys_integration adapters represent an SDOM case as
an infrasys System with typed components, time series, and attached results.
They support system-centric persistence, result inspection, and plotting while
delegating optimization to the established SDOM Pyomo and solver pipeline.
flowchart LR
CSV[SDOM CSV inputs] --> System[infrasys System]
System --> Builder[Pyomo AbstractModel builder]
Builder --> Solver[Solver]
Solver --> Attributes[System result attributes]
Attributes --> Rebuild[Reconstructed OptimizationResults]
Rebuild --> Plots[Plots]
Data Model
An infrasys System owns the typed input components that define an SDOM
scenario. Every SDOM component inherits the shared name, optional category,
and JSON-serializable ext metadata fields from SDOMComponent. Loads,
generators, storage, and import/export interfaces connect to a bus; each bus
belongs to an area. Time series are attached to the components that use them.
classDiagram
class Component
class SDOMComponent
class SDOMArea
class SDOMBus
class SDOMLoad
class SDOMGenerator
class SDOMStorage
class SDOMImportInterface
class SDOMExportInterface
class SDOMTransmissionInterface
Component <|-- SDOMComponent
SDOMComponent <|-- SDOMArea
SDOMComponent <|-- SDOMBus
SDOMComponent <|-- SDOMLoad
SDOMComponent <|-- SDOMGenerator
SDOMComponent <|-- SDOMStorage
SDOMComponent <|-- SDOMImportInterface
SDOMComponent <|-- SDOMExportInterface
SDOMComponent <|-- SDOMTransmissionInterface
SDOMBus --> SDOMArea : belongs to
SDOMLoad --> SDOMBus : connects to
SDOMGenerator --> SDOMBus : connects to
SDOMStorage --> SDOMBus : connects to
The generator subclasses are SDOMThermalGenerator, SDOMSolarGenerator,
SDOMWindGenerator, SDOMHydroGenerator, SDOMNuclearGenerator, and
SDOMOtherRenewableGenerator. SDOMThermalGenerator requires heat-rate and
fuel-cost inputs, while SDOMHydroGenerator can record a budget period.
SDOMScalarParameter and SDOMFormulationConfig store scalar input values
and formulation selections outside the physical network hierarchy.
Units and Result Displays
Physical infrasys component fields carry r2x-core Unit metadata. This
metadata supports typed component validation and display; it does not change
the base numeric-unit conventions of SDOM optimization input CSV files.
Solved OptimizationResults objects optionally expose display metadata through
attribute_units and get_attribute_unit(name). SDOM collectors populate
MW for installed and storage power capacities, MWh for storage energy and
generation totals, and USD for cost breakdowns. Plotting helpers use this
metadata when it is available and retain their existing labels for directly
constructed or legacy-deserialized result objects without it.
Result Attributes
add_results_to_system stores a solved OptimizationResults instance as
typed supplemental attributes. Every SDOMResultAttribute includes run_id
and may include scenario_name and case_name; use run_id to keep several
result sets on one System. Attributes are owned by the System or the component
whose result they describe, then optimization_results_from_system rebuilds
the legacy-compatible result object.
flowchart TD
Results[OptimizationResults] --> Attach[Attach typed result attributes]
Attach --> System[System owned attributes]
Attach --> Assets[Area and asset owned attributes]
System --> Rebuild[Rebuild OptimizationResults]
Assets --> Rebuild
Rebuild --> Query[Query or plot results]
Result attribute |
Owner |
Key fields |
|---|---|---|
|
System |
Caller-supplied JSON-serializable |
|
System |
|
|
System |
Solver problem-info |
|
System |
|
|
System or area |
|
|
System or area |
|
|
System or area |
|
|
System |
Original |
|
Generator or storage |
|
|
Area |
Ordered |
|
Thermal generator |
Ordered |
|
Storage |
Ordered |
|
Transmission interface |
Ordered |
|
System or area |
|
Hourly result vectors are validated to match their hours vector. Area dispatch
also rejects duplicate metrics. GeographicInfo is a separate supplemental
attribute for component location; it stores a GeoJSON Point and an optional
data source, rather than optimization output.
Compatibility policy
In SDOM v0.2.XX, the System APIs are opt-in adapters and existing load_data,
initialize_model, run_solver, and legacy ParametricStudy dict/CSV
workflows remain supported. This is a planned migration notice: beginning with
SDOM v0.3.0, the System/Infrasys interface becomes the primary supported
interface and the dict-based load_data/initialize_model workflow is
deprecated. New scripts should use the System workflows below; this notice does
not change the runtime behavior of the current v0.2.XX release.
flowchart TD
Start[Choose an SDOM workflow] --> System[Use System workflow]
Start --> Legacy[Maintain legacy script]
System --> Adapted[load_system to builder to run_solver]
Legacy --> Existing[load_data to initialize_model to run_solver]
First workflow
Choose the copperplate example for a single-area scenario and the zonal
example when the scenario defines areas and a network. Both are runnable
24-hour System-first workflows; install the optional integration dependencies
with uv pip install "sdom[infrasys]" before running them.
Copperplate workflow
Load a single-area CSV scenario directly into a System, create the
copperplate builder, instantiate it once, solve, and attach the returned
OptimizationResults. Data/no_exchange_run_of_river is a repository
example input directory.
from sdom import get_default_solver_config_dict, run_solver
from sdom.infrasys_integration import (
add_results_to_system,
optimization_results_from_system,
plot_system_results,
query_result_attributes,
)
from sdom.infrasys_integration.make_system import load_system
from sdom.infrasys_integration.pyomo_builder import (
initialize_copperplate_model_from_system,
)
system = load_system("Data/no_exchange_run_of_river", name="copperplate")
builder = initialize_copperplate_model_from_system(system, n_hours=24)
model = builder.create_instance()
solver_config = get_default_solver_config_dict(
solver_name="highs", executable_path=""
)
results = run_solver(model, solver_config, case_name="copperplate")
add_results_to_system(system, results, run_id="copperplate-24h")
restored_results = optimization_results_from_system(
system, run_id="copperplate-24h"
)
attributes = query_result_attributes(system, run_id="copperplate-24h")
plot_system_results(system, run_id="copperplate-24h", output_dir="results/copperplate")
restored_results is an OptimizationResults object reconstructed from the
supplemental attributes; attributes contains the corresponding typed result
attributes. Use a distinct run_id for each result set retained on a System.
Zonal workflow
Use initialize_model_from_system for data whose network formulation and
areas define the model, including the repository’s Data/zonal_test example.
The solver, attachment, reconstruction, and plot APIs are the same. When
results are zonal, plot_system_results also emits area stacks and line-flow
plots.
from sdom import get_default_solver_config_dict, run_solver
from sdom.infrasys_integration import (
add_results_to_system,
optimization_results_from_system,
plot_system_results,
)
from sdom.infrasys_integration.make_system import load_system
from sdom.infrasys_integration.pyomo_builder import initialize_model_from_system
system = load_system("Data/zonal_test", name="zonal")
model = initialize_model_from_system(system, n_hours=24).create_instance()
solver_config = get_default_solver_config_dict(
solver_name="highs", executable_path=""
)
results = run_solver(model, solver_config, case_name="zonal")
add_results_to_system(system, results, run_id="zonal-24h")
restored_results = optimization_results_from_system(system, run_id="zonal-24h")
plot_system_results(system, run_id="zonal-24h", output_dir="results/zonal")
System persistence and builder lifecycle
The tested infrasys JSON persistence format is System.to_json(path, overwrite=True) and System.from_json(path). It round-trips System
components, associations, and queryable time-series metadata for both the
copperplate and zonal examples.
from pathlib import Path
from infrasys import System
from sdom.infrasys_integration.make_system import load_system
system = load_system("Data/no_exchange_run_of_river", name="copperplate")
path = Path("results/copperplate-system.json")
system.to_json(path, overwrite=True)
loaded_system = System.from_json(path)
Build a model only after completing System adapter operations that require the
retained compatibility source data. Calling create_instance() releases that
backing source data from both the builder and System. Consequently,
system_to_data_dict, SystemParametricStudy, and the System sweep helpers
must be used before model instantiation. JSON persistence is shown separately
above; do not assume an arbitrary deserialized System retains the adapter’s
in-memory source-data dictionary.
System parametric studies
SystemParametricStudy delegates case execution to the legacy
ParametricStudy, returning list[OptimizationResults]. Attach its results to
the original System before creating sensitivity plots. On Windows, place
study.run() behind an if __name__ == "__main__": guard because the legacy
study may start worker processes.
flowchart LR
Cases[System parametric cases] --> Solve[Study run]
Solve --> Attached[Attached scenarios and results]
Attached --> Sensitivity[Sensitivity plots]
from sdom import get_default_solver_config_dict
from sdom.infrasys_integration import (
SystemParametricStudy,
add_parametric_results_to_system,
plot_system_parametric_results,
)
from sdom.infrasys_integration.make_system import load_system
def main():
system = load_system("Data/no_exchange_run_of_river")
solver_config = get_default_solver_config_dict(
solver_name="highs", executable_path=""
)
study = SystemParametricStudy(
system, solver_config, n_hours=24, output_dir="results/parametric", n_cores=1
)
study.add_genmix_sweep([0.8, 1.0])
results = study.run()
add_parametric_results_to_system(
system, study, results=results, run_id="genmix-24h"
)
plot_system_parametric_results(
system,
run_id="genmix-24h",
group_by="GenMix_Target",
output_dir="results/parametric",
)
if __name__ == "__main__":
main()
The study stores per-case metadata and the attachment assigns stable scenario
identifiers within run_id; plot_system_parametric_results reconstructs
those cases and delegates rendering to SDOM’s sensitivity plotter.
Migrating a dict workflow
Keep the legacy path unchanged, or replace only its loading and model-building steps with their System equivalents. The solver still receives the concrete Pyomo model, and result export remains available through existing SDOM APIs.
Legacy dict/CSV workflow |
Optional System workflow |
|---|---|
|
|
|
|
|
Same |
Use |
Attach, query, reconstruct, and plot through System adapters |
|
|
|
|
For an explicit dict-to-System transition, load_system_from_data(data) builds
a System from the dictionary returned by load_data. Before instantiation,
apply_scalar_sweep_to_system and apply_time_series_sweep_to_system create
new Systems with copied backing data; they do not mutate the source System.
See the infrasys integration API for the complete adapter reference.