Policy Graphs - Running
The data for this case is available in the folder
data/case_6
Recap
In this tutorial, we explore the differences between two types of policy graphs, linear and cyclic, using a simple model with varying numbers of periods. The model contains one zone, one bus, one demand point, one hydro unit, and one thermal unit. We will analyze how changes in policy graph types affect the decision-making process in centralized operations, focusing on the impact of different configurations of periods.
We'll start by importing the necessary packages.
using Dates
using DataFrames
using IARA
First, let's create a folder that will contain the execution for each iteration.
const PATH_ORIGINAL = joinpath(@__DIR__, "data", "case_6")
const PATH_EXECUTION = joinpath(@__DIR__, "case_6_execution")
if !isdir(PATH_EXECUTION)
mkdir(PATH_EXECUTION)
end
"/home/runner/work/IARA.jl/IARA.jl/docs/build/tutorial/case_6_execution"
Running the Case: Linear Policy Graph with 2 Stages
Let's create a copy of the original case.
const PATH_LINEAR_2 = joinpath(PATH_EXECUTION, "linear_2")
if !isdir(PATH_LINEAR_2)
mkdir(PATH_LINEAR_2)
end
cp(PATH_ORIGINAL, PATH_LINEAR_2; force = true);
In the previous section we created a case with 2 periods and a linear policy graph. Therefore, we do not need to update the number of periods or the policy graph type.
Let's begin by running the case with a linear policy graph and 2 periods. This scenario simulates a situation where decision-making happens over two periods with no cyclic behavior.
IARA.train_min_cost(PATH_LINEAR_2)
[ Info:
[ Info: Execution options
[ Info: Path: /home/runner/work/IARA.jl/IARA.jl/docs/build/tutorial/case_6_execution/linear_2
[ Info: Output path: /home/runner/work/IARA.jl/IARA.jl/docs/build/tutorial/case_6_execution/linear_2/outputs
[ Info: Run mode: TRAIN_MIN_COST
[ Info: Plot results: true
[ Info: periods: 2
[ Info: scenarios: 3
[ Info: subperiods: 1
[ Info:
[ Info: Collections
[ Info: HydroUnit: 1 element(s)
[ Info: ThermalUnit: 2 element(s)
[ Info: Zone: 1 element(s)
[ Info: Bus: 1 element(s)
[ Info: DemandUnit: 1 element(s)
[ Info: GaugingStation: 1 element(s)
[ Info:
[ Info: Time Series from external files
[ Info: inflow
[ Info: demand_unit
[ Info:
[ Info: Cuts file:
[ Info: No cuts file
[ Info:
-------------------------------------------------------------------
SDDP.jl (c) Oscar Dowson and contributors, 2017-24
-------------------------------------------------------------------
problem
nodes : 2
state variables : 1
scenarios : 9.00000e+00
existing cuts : false
options
solver : serial mode
risk measure : SDDP.Expectation()
sampling scheme : SDDP.InSampleMonteCarlo
subproblem structure
VariableRef : [13, 13]
JuMP.AffExpr in MOI.EqualTo{Float64} : [4, 4]
JuMP.VariableRef in MOI.GreaterThan{Float64} : [10, 10]
JuMP.VariableRef in MOI.LessThan{Float64} : [6, 7]
JuMP.VariableRef in MOI.Parameter{Float64} : [2, 2]
numerical stability report
matrix range [1e+00, 1e+03]
objective range [1e-02, 9e+02]
bounds range [1e+01, 1e+03]
rhs range [0e+00, 0e+00]
-------------------------------------------------------------------
iteration simulation bound time (s) solves pid
-------------------------------------------------------------------
1 5.301372e+03 4.454544e+00 5.961895e-03 8 1
40 3.528934e+01 3.528934e+01 8.378100e-02 356 1
-------------------------------------------------------------------
status : simulation_stopping
total time (s) : 8.378100e-02
total solves : 356
best bound : 3.528934e+01
simulation ci : 1.782192e+02 ± 2.584177e+02
numeric issues : 0
-------------------------------------------------------------------
[ Info: Running post-processing routines
[ Info: Building plots
Analyzing the results
Here's the graph of the final volume at each period
hydro_final_volume_all =
IARA.custom_plot(
hydro_final_volume_all,
IARA.PlotTimeSeriesMean;
title = "Reservoir Final Volume",
agents = ["Hydro1"],
period = 1:2,
)
For this case, the optimal strategy for the hydro unit is to release water in the last period. This happens because there are no future costs associated with the last period, encouraging full use of available resources.
Running the Case: Linear Policy Graph with 10 Stages
Next, we increase the number of periods to 10 while keeping the policy graph linear. This allows us to see how a longer planning horizon influences the decision-making process.
const PATH_LINEAR_10 = joinpath(PATH_EXECUTION, "linear_10")
if !isdir(PATH_LINEAR_10)
mkdir(PATH_LINEAR_10)
end
cp(PATH_ORIGINAL, PATH_LINEAR_10; force = true);
Now we need to update the number of periods to 10.
db = IARA.load_study(PATH_LINEAR_10; read_only = false)
IARA.update_configuration!(
db;
number_of_periods = 10,
)
PSRClassesInterface.PSRDatabaseSQLite.DatabaseSQLite(SQLite.DB("/home/runner/work/IARA.jl/IARA.jl/docs/build/tutorial/case_6_execution/linear_10/study.iara"), "/home/runner/work/IARA.jl/IARA.jl/docs/build/tutorial/case_6_execution/linear_10/study.iara", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.Collection}("Configuration" => PSRClassesInterface.PSRDatabaseSQLite.Collection("Configuration", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "Configuration", "Configuration"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, "\"Configuration\"", true, "Configuration", "Configuration"), "number_of_nodes" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("number_of_nodes", Int64, missing, false, "Configuration", "Configuration"), "number_of_subscenarios" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("number_of_subscenarios", Int64, 1, true, "Configuration", "Configuration"), "iteration_limit" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("iteration_limit", Int64, missing, false, "Configuration", "Configuration"), "initial_date_time" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("initial_date_time", String, "\"2024-01-01\"", true, "Configuration", "Configuration"), "period_type" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("period_type", Int64, 0, true, "Configuration", "Configuration"), "hydro_balance_subperiod_resolution" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("hydro_balance_subperiod_resolution", Int64, 0, false, "Configuration", "Configuration"), "use_binary_variables" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("use_binary_variables", Int64, 0, true, "Configuration", "Configuration"), "loop_subperiods_for_thermal_constraints" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("loop_subperiods_for_thermal_constraints", Int64, missing, false, "Configuration", "Configuration")…), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}("subperiod_duration_in_hours" => PSRClassesInterface.PSRDatabaseSQLite.VectorParameter{Float64}("subperiod_duration_in_hours", Float64, missing, false, "subperiod_duration", "Configuration", "Configuration_vector_subperiod_duration"), "expected_number_of_repeats_per_node" => PSRClassesInterface.PSRDatabaseSQLite.VectorParameter{Int64}("expected_number_of_repeats_per_node", Int64, missing, false, "expected_number_of_repeats_per_node", "Configuration", "Configuration_vector_expected_number_of_repeats_per_node")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}("hour_subperiod_map" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile{String}("hour_subperiod_map", String, missing, false, "Configuration", "Configuration_time_series_files"), "fcf_cuts" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile{String}("fcf_cuts", String, missing, false, "Configuration", "Configuration_time_series_files"))), "RenewableUnit" => PSRClassesInterface.PSRDatabaseSQLite.Collection("RenewableUnit", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "RenewableUnit", "RenewableUnit"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, missing, true, "RenewableUnit", "RenewableUnit"), "technology_type" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("technology_type", Int64, missing, false, "RenewableUnit", "RenewableUnit")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}("biddinggroup_id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("biddinggroup_id", Int64, missing, false, "RenewableUnit", "BiddingGroup", "id", "RenewableUnit"), "bus_id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("bus_id", Int64, missing, false, "RenewableUnit", "Bus", "id", "RenewableUnit")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}("existing" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Int64}("existing", Int64, missing, false, "parameters", "RenewableUnit", "RenewableUnit_time_series_parameters", ["date_time"], 1), "max_generation" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("max_generation", Float64, missing, false, "parameters", "RenewableUnit", "RenewableUnit_time_series_parameters", ["date_time"], 1), "om_cost" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("om_cost", Float64, missing, false, "parameters", "RenewableUnit", "RenewableUnit_time_series_parameters", ["date_time"], 1), "curtailment_cost" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("curtailment_cost", Float64, missing, false, "parameters", "RenewableUnit", "RenewableUnit_time_series_parameters", ["date_time"], 1)), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}("generation" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile{String}("generation", String, missing, true, "RenewableUnit", "RenewableUnit_time_series_files"))), "HydroUnit" => PSRClassesInterface.PSRDatabaseSQLite.Collection("HydroUnit", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "HydroUnit", "HydroUnit"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, missing, true, "HydroUnit", "HydroUnit"), "initial_volume" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("initial_volume", Float64, missing, false, "HydroUnit", "HydroUnit"), "initial_volume_type" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("initial_volume_type", Int64, 2, false, "HydroUnit", "HydroUnit"), "has_commitment" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("has_commitment", Int64, 0, false, "HydroUnit", "HydroUnit"), "operation_type" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("operation_type", Int64, 0, false, "HydroUnit", "HydroUnit")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}("hydrounit_spill_to" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("hydrounit_spill_to", Int64, missing, false, "HydroUnit", "HydroUnit", "spill_to", "HydroUnit"), "hydrounit_turbine_to" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("hydrounit_turbine_to", Int64, missing, false, "HydroUnit", "HydroUnit", "turbine_to", "HydroUnit"), "gaugingstation_id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("gaugingstation_id", Int64, missing, false, "HydroUnit", "GaugingStation", "id", "HydroUnit"), "biddinggroup_id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("biddinggroup_id", Int64, missing, false, "HydroUnit", "BiddingGroup", "id", "HydroUnit"), "bus_id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("bus_id", Int64, missing, false, "HydroUnit", "Bus", "id", "HydroUnit")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}("waveguide_volume" => PSRClassesInterface.PSRDatabaseSQLite.VectorParameter{Float64}("waveguide_volume", Float64, missing, true, "waveguide", "HydroUnit", "HydroUnit_vector_waveguide")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}("existing" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Int64}("existing", Int64, missing, false, "parameters", "HydroUnit", "HydroUnit_time_series_parameters", ["date_time"], 1), "production_factor" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("production_factor", Float64, missing, false, "parameters", "HydroUnit", "HydroUnit_time_series_parameters", ["date_time"], 1), "min_generation" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("min_generation", Float64, missing, false, "parameters", "HydroUnit", "HydroUnit_time_series_parameters", ["date_time"], 1), "max_generation" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("max_generation", Float64, missing, false, "parameters", "HydroUnit", "HydroUnit_time_series_parameters", ["date_time"], 1), "max_turbining" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("max_turbining", Float64, missing, false, "parameters", "HydroUnit", "HydroUnit_time_series_parameters", ["date_time"], 1), "min_volume" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("min_volume", Float64, missing, false, "parameters", "HydroUnit", "HydroUnit_time_series_parameters", ["date_time"], 1), "max_volume" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("max_volume", Float64, missing, false, "parameters", "HydroUnit", "HydroUnit_time_series_parameters", ["date_time"], 1), "min_outflow" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("min_outflow", Float64, missing, false, "parameters", "HydroUnit", "HydroUnit_time_series_parameters", ["date_time"], 1), "om_cost" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("om_cost", Float64, missing, false, "parameters", "HydroUnit", "HydroUnit_time_series_parameters", ["date_time"], 1)), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}("inflow" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile{String}("inflow", String, missing, true, "HydroUnit", "HydroUnit_time_series_files"))), "GaugingStation" => PSRClassesInterface.PSRDatabaseSQLite.Collection("GaugingStation", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "GaugingStation", "GaugingStation"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, missing, true, "GaugingStation", "GaugingStation")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}("gaugingstation_downstream" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("gaugingstation_downstream", Int64, missing, false, "GaugingStation", "GaugingStation", "downstream", "GaugingStation")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}("historical_inflow" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("historical_inflow", Float64, missing, false, "historical_inflow", "GaugingStation", "GaugingStation_time_series_historical_inflow", ["date_time"], 1)), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}()), "ThermalUnit" => PSRClassesInterface.PSRDatabaseSQLite.Collection("ThermalUnit", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "ThermalUnit", "ThermalUnit"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, missing, true, "ThermalUnit", "ThermalUnit"), "has_commitment" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("has_commitment", Int64, 0, true, "ThermalUnit", "ThermalUnit"), "max_ramp_up" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("max_ramp_up", Float64, missing, false, "ThermalUnit", "ThermalUnit"), "max_ramp_down" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("max_ramp_down", Float64, missing, false, "ThermalUnit", "ThermalUnit"), "min_uptime" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("min_uptime", Float64, missing, false, "ThermalUnit", "ThermalUnit"), "max_uptime" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("max_uptime", Float64, missing, false, "ThermalUnit", "ThermalUnit"), "min_downtime" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("min_downtime", Float64, missing, false, "ThermalUnit", "ThermalUnit"), "max_startups" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("max_startups", Int64, missing, false, "ThermalUnit", "ThermalUnit"), "max_shutdowns" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("max_shutdowns", Int64, missing, false, "ThermalUnit", "ThermalUnit")…), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}("biddinggroup_id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("biddinggroup_id", Int64, missing, false, "ThermalUnit", "BiddingGroup", "id", "ThermalUnit"), "bus_id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("bus_id", Int64, missing, false, "ThermalUnit", "Bus", "id", "ThermalUnit")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}("existing" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Int64}("existing", Int64, missing, false, "parameters", "ThermalUnit", "ThermalUnit_time_series_parameters", ["date_time"], 1), "startup_cost" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("startup_cost", Float64, missing, false, "parameters", "ThermalUnit", "ThermalUnit_time_series_parameters", ["date_time"], 1), "min_generation" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("min_generation", Float64, missing, false, "parameters", "ThermalUnit", "ThermalUnit_time_series_parameters", ["date_time"], 1), "max_generation" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("max_generation", Float64, missing, false, "parameters", "ThermalUnit", "ThermalUnit_time_series_parameters", ["date_time"], 1), "om_cost" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("om_cost", Float64, missing, false, "parameters", "ThermalUnit", "ThermalUnit_time_series_parameters", ["date_time"], 1)), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}()), "DemandUnit" => PSRClassesInterface.PSRDatabaseSQLite.Collection("DemandUnit", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "DemandUnit", "DemandUnit"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, missing, true, "DemandUnit", "DemandUnit"), "demand_unit_type" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("demand_unit_type", Int64, 0, true, "DemandUnit", "DemandUnit"), "max_shift_up" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("max_shift_up", Float64, missing, false, "DemandUnit", "DemandUnit"), "max_shift_down" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("max_shift_down", Float64, missing, false, "DemandUnit", "DemandUnit"), "curtailment_cost" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("curtailment_cost", Float64, missing, false, "DemandUnit", "DemandUnit"), "max_curtailment" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("max_curtailment", Float64, missing, false, "DemandUnit", "DemandUnit")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}("bus_id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("bus_id", Int64, missing, false, "DemandUnit", "Bus", "id", "DemandUnit")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}("existing" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Int64}("existing", Int64, missing, false, "parameters", "DemandUnit", "DemandUnit_time_series_parameters", ["date_time"], 1)), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}("demand" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile{String}("demand", String, missing, true, "DemandUnit", "DemandUnit_time_series_files"), "elastic_demand_price" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile{String}("elastic_demand_price", String, missing, false, "DemandUnit", "DemandUnit_time_series_files"), "demand_window" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile{String}("demand_window", String, missing, false, "DemandUnit", "DemandUnit_time_series_files"))), "Zone" => PSRClassesInterface.PSRDatabaseSQLite.Collection("Zone", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "Zone", "Zone"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, missing, true, "Zone", "Zone")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}()), "Bus" => PSRClassesInterface.PSRDatabaseSQLite.Collection("Bus", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "Bus", "Bus"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, missing, true, "Bus", "Bus")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}("zone_id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("zone_id", Int64, missing, false, "Bus", "Zone", "id", "Bus")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}()), "DCLine" => PSRClassesInterface.PSRDatabaseSQLite.Collection("DCLine", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "DCLine", "DCLine"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, missing, true, "DCLine", "DCLine")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}("bus_from" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("bus_from", Int64, missing, false, "DCLine", "Bus", "from", "DCLine"), "bus_to" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("bus_to", Int64, missing, false, "DCLine", "Bus", "to", "DCLine")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}("existing" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Int64}("existing", Int64, missing, false, "parameters", "DCLine", "DCLine_time_series_parameters", ["date_time"], 1), "capacity_to" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("capacity_to", Float64, missing, false, "parameters", "DCLine", "DCLine_time_series_parameters", ["date_time"], 1), "capacity_from" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("capacity_from", Float64, missing, false, "parameters", "DCLine", "DCLine_time_series_parameters", ["date_time"], 1)), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}()), "Branch" => PSRClassesInterface.PSRDatabaseSQLite.Collection("Branch", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "Branch", "Branch"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, missing, true, "Branch", "Branch"), "line_model" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("line_model", Int64, 0, true, "Branch", "Branch")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}("bus_from" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("bus_from", Int64, missing, false, "Branch", "Bus", "from", "Branch"), "bus_to" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("bus_to", Int64, missing, false, "Branch", "Bus", "to", "Branch")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}("existing" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Int64}("existing", Int64, missing, false, "parameters", "Branch", "Branch_time_series_parameters", ["date_time"], 1), "capacity" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("capacity", Float64, missing, false, "parameters", "Branch", "Branch_time_series_parameters", ["date_time"], 1), "reactance" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("reactance", Float64, missing, false, "parameters", "Branch", "Branch_time_series_parameters", ["date_time"], 1)), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}())…), false, PSRClassesInterface.PSRDatabaseSQLite.TimeController(Dict{Tuple{String, String}, PSRClassesInterface.PSRDatabaseSQLite.TimeControllerCache}(), Dict{String, Bool}()))
We will also update the inflow and demand time series files to have 10 periods.
IARA.link_time_series_to_file(
db,
"DemandUnit";
demand = "demands_10_periods",
)
IARA.link_time_series_to_file(
db,
"HydroUnit";
inflow = "inflow_10_periods",
)
IARA.close_study!(db)
Let's run the case.
IARA.train_min_cost(PATH_LINEAR_10)
[ Info:
[ Info: Execution options
[ Info: Path: /home/runner/work/IARA.jl/IARA.jl/docs/build/tutorial/case_6_execution/linear_10
[ Info: Output path: /home/runner/work/IARA.jl/IARA.jl/docs/build/tutorial/case_6_execution/linear_10/outputs
[ Info: Run mode: TRAIN_MIN_COST
[ Info: Plot results: true
[ Info: periods: 10
[ Info: scenarios: 3
[ Info: subperiods: 1
[ Info:
[ Info: Collections
[ Info: HydroUnit: 1 element(s)
[ Info: ThermalUnit: 2 element(s)
[ Info: Zone: 1 element(s)
[ Info: Bus: 1 element(s)
[ Info: DemandUnit: 1 element(s)
[ Info: GaugingStation: 1 element(s)
[ Info:
[ Info: Time Series from external files
[ Info: inflow
[ Info: demand_unit
[ Info:
[ Info: Cuts file:
[ Info: No cuts file
[ Info:
-------------------------------------------------------------------
SDDP.jl (c) Oscar Dowson and contributors, 2017-24
-------------------------------------------------------------------
problem
nodes : 10
state variables : 1
scenarios : 5.90490e+04
existing cuts : false
options
solver : serial mode
risk measure : SDDP.Expectation()
sampling scheme : SDDP.InSampleMonteCarlo
subproblem structure
VariableRef : [13, 13]
JuMP.AffExpr in MOI.EqualTo{Float64} : [4, 4]
JuMP.VariableRef in MOI.GreaterThan{Float64} : [10, 10]
JuMP.VariableRef in MOI.LessThan{Float64} : [6, 7]
JuMP.VariableRef in MOI.Parameter{Float64} : [2, 2]
numerical stability report
matrix range [1e+00, 1e+03]
objective range [8e-03, 9e+02]
bounds range [1e+01, 1e+03]
rhs range [0e+00, 0e+00]
-------------------------------------------------------------------
iteration simulation bound time (s) solves pid
-------------------------------------------------------------------
1 2.420244e+04 6.060909e+03 2.317023e-02 40 1
40 9.408470e+03 9.408470e+03 8.100932e-01 3600 1
-------------------------------------------------------------------
status : simulation_stopping
total time (s) : 8.100932e-01
total solves : 3600
best bound : 9.408470e+03
simulation ci : 9.807392e+03 ± 7.256825e+02
numeric issues : 0
-------------------------------------------------------------------
[ Info: Running post-processing routines
[ Info: Building plots
Analyzing the results
Here's the graph of the final volume at each period
hydro_final_volume_all =
IARA.custom_plot(
hydro_final_volume_all,
IARA.PlotTimeSeriesMean;
title = "Reservoir Final Volume",
agents = ["Hydro1"],
period = 1:2,
)
With 10 periods, the model accounts for a longer planning horizon, influencing the decision to release water more conservatively in earlier periods. The hydro unit no longer empties the reservoir in a single burst but instead manages water levels more carefully over time, anticipating future periods.
IARA.custom_plot(
hydro_final_volume_all,
IARA.PlotTimeSeriesMean;
title = "Reservoir Final Volume",
agents = ["Hydro1"],
period = 3:10,
)
As the planning horizon progresses, the model becomes more aggressive in its approach, depleting the reservoir by the end of the fourth year.
Running the Case: Cyclic Policy Graph with 2 Stages
Now, we will switch the policy graph to cyclic, which assumes that the decision-making process repeats over time.
const PATH_CYCLIC_2 = joinpath(PATH_EXECUTION, "cyclic_2")
if !isdir(PATH_CYCLIC_2)
mkdir(PATH_CYCLIC_2)
end
cp(PATH_ORIGINAL, PATH_CYCLIC_2; force = true);
Now we need to update the policy graph type to CYCLIC_WITH_FIXED_ROOT
.
db = IARA.load_study(PATH_CYCLIC_2; read_only = false)
IARA.update_configuration!(
db;
number_of_periods = 2,
policy_graph_type = IARA.Configurations_PolicyGraphType.CYCLIC_WITH_FIXED_ROOT,
)
PSRClassesInterface.PSRDatabaseSQLite.DatabaseSQLite(SQLite.DB("/home/runner/work/IARA.jl/IARA.jl/docs/build/tutorial/case_6_execution/cyclic_2/study.iara"), "/home/runner/work/IARA.jl/IARA.jl/docs/build/tutorial/case_6_execution/cyclic_2/study.iara", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.Collection}("Configuration" => PSRClassesInterface.PSRDatabaseSQLite.Collection("Configuration", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "Configuration", "Configuration"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, "\"Configuration\"", true, "Configuration", "Configuration"), "number_of_nodes" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("number_of_nodes", Int64, missing, false, "Configuration", "Configuration"), "number_of_subscenarios" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("number_of_subscenarios", Int64, 1, true, "Configuration", "Configuration"), "iteration_limit" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("iteration_limit", Int64, missing, false, "Configuration", "Configuration"), "initial_date_time" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("initial_date_time", String, "\"2024-01-01\"", true, "Configuration", "Configuration"), "period_type" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("period_type", Int64, 0, true, "Configuration", "Configuration"), "hydro_balance_subperiod_resolution" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("hydro_balance_subperiod_resolution", Int64, 0, false, "Configuration", "Configuration"), "use_binary_variables" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("use_binary_variables", Int64, 0, true, "Configuration", "Configuration"), "loop_subperiods_for_thermal_constraints" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("loop_subperiods_for_thermal_constraints", Int64, missing, false, "Configuration", "Configuration")…), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}("subperiod_duration_in_hours" => PSRClassesInterface.PSRDatabaseSQLite.VectorParameter{Float64}("subperiod_duration_in_hours", Float64, missing, false, "subperiod_duration", "Configuration", "Configuration_vector_subperiod_duration"), "expected_number_of_repeats_per_node" => PSRClassesInterface.PSRDatabaseSQLite.VectorParameter{Int64}("expected_number_of_repeats_per_node", Int64, missing, false, "expected_number_of_repeats_per_node", "Configuration", "Configuration_vector_expected_number_of_repeats_per_node")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}("hour_subperiod_map" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile{String}("hour_subperiod_map", String, missing, false, "Configuration", "Configuration_time_series_files"), "fcf_cuts" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile{String}("fcf_cuts", String, missing, false, "Configuration", "Configuration_time_series_files"))), "RenewableUnit" => PSRClassesInterface.PSRDatabaseSQLite.Collection("RenewableUnit", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "RenewableUnit", "RenewableUnit"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, missing, true, "RenewableUnit", "RenewableUnit"), "technology_type" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("technology_type", Int64, missing, false, "RenewableUnit", "RenewableUnit")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}("biddinggroup_id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("biddinggroup_id", Int64, missing, false, "RenewableUnit", "BiddingGroup", "id", "RenewableUnit"), "bus_id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("bus_id", Int64, missing, false, "RenewableUnit", "Bus", "id", "RenewableUnit")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}("existing" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Int64}("existing", Int64, missing, false, "parameters", "RenewableUnit", "RenewableUnit_time_series_parameters", ["date_time"], 1), "max_generation" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("max_generation", Float64, missing, false, "parameters", "RenewableUnit", "RenewableUnit_time_series_parameters", ["date_time"], 1), "om_cost" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("om_cost", Float64, missing, false, "parameters", "RenewableUnit", "RenewableUnit_time_series_parameters", ["date_time"], 1), "curtailment_cost" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("curtailment_cost", Float64, missing, false, "parameters", "RenewableUnit", "RenewableUnit_time_series_parameters", ["date_time"], 1)), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}("generation" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile{String}("generation", String, missing, true, "RenewableUnit", "RenewableUnit_time_series_files"))), "HydroUnit" => PSRClassesInterface.PSRDatabaseSQLite.Collection("HydroUnit", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "HydroUnit", "HydroUnit"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, missing, true, "HydroUnit", "HydroUnit"), "initial_volume" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("initial_volume", Float64, missing, false, "HydroUnit", "HydroUnit"), "initial_volume_type" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("initial_volume_type", Int64, 2, false, "HydroUnit", "HydroUnit"), "has_commitment" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("has_commitment", Int64, 0, false, "HydroUnit", "HydroUnit"), "operation_type" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("operation_type", Int64, 0, false, "HydroUnit", "HydroUnit")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}("hydrounit_spill_to" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("hydrounit_spill_to", Int64, missing, false, "HydroUnit", "HydroUnit", "spill_to", "HydroUnit"), "hydrounit_turbine_to" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("hydrounit_turbine_to", Int64, missing, false, "HydroUnit", "HydroUnit", "turbine_to", "HydroUnit"), "gaugingstation_id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("gaugingstation_id", Int64, missing, false, "HydroUnit", "GaugingStation", "id", "HydroUnit"), "biddinggroup_id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("biddinggroup_id", Int64, missing, false, "HydroUnit", "BiddingGroup", "id", "HydroUnit"), "bus_id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("bus_id", Int64, missing, false, "HydroUnit", "Bus", "id", "HydroUnit")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}("waveguide_volume" => PSRClassesInterface.PSRDatabaseSQLite.VectorParameter{Float64}("waveguide_volume", Float64, missing, true, "waveguide", "HydroUnit", "HydroUnit_vector_waveguide")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}("existing" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Int64}("existing", Int64, missing, false, "parameters", "HydroUnit", "HydroUnit_time_series_parameters", ["date_time"], 1), "production_factor" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("production_factor", Float64, missing, false, "parameters", "HydroUnit", "HydroUnit_time_series_parameters", ["date_time"], 1), "min_generation" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("min_generation", Float64, missing, false, "parameters", "HydroUnit", "HydroUnit_time_series_parameters", ["date_time"], 1), "max_generation" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("max_generation", Float64, missing, false, "parameters", "HydroUnit", "HydroUnit_time_series_parameters", ["date_time"], 1), "max_turbining" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("max_turbining", Float64, missing, false, "parameters", "HydroUnit", "HydroUnit_time_series_parameters", ["date_time"], 1), "min_volume" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("min_volume", Float64, missing, false, "parameters", "HydroUnit", "HydroUnit_time_series_parameters", ["date_time"], 1), "max_volume" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("max_volume", Float64, missing, false, "parameters", "HydroUnit", "HydroUnit_time_series_parameters", ["date_time"], 1), "min_outflow" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("min_outflow", Float64, missing, false, "parameters", "HydroUnit", "HydroUnit_time_series_parameters", ["date_time"], 1), "om_cost" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("om_cost", Float64, missing, false, "parameters", "HydroUnit", "HydroUnit_time_series_parameters", ["date_time"], 1)), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}("inflow" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile{String}("inflow", String, missing, true, "HydroUnit", "HydroUnit_time_series_files"))), "GaugingStation" => PSRClassesInterface.PSRDatabaseSQLite.Collection("GaugingStation", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "GaugingStation", "GaugingStation"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, missing, true, "GaugingStation", "GaugingStation")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}("gaugingstation_downstream" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("gaugingstation_downstream", Int64, missing, false, "GaugingStation", "GaugingStation", "downstream", "GaugingStation")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}("historical_inflow" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("historical_inflow", Float64, missing, false, "historical_inflow", "GaugingStation", "GaugingStation_time_series_historical_inflow", ["date_time"], 1)), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}()), "ThermalUnit" => PSRClassesInterface.PSRDatabaseSQLite.Collection("ThermalUnit", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "ThermalUnit", "ThermalUnit"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, missing, true, "ThermalUnit", "ThermalUnit"), "has_commitment" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("has_commitment", Int64, 0, true, "ThermalUnit", "ThermalUnit"), "max_ramp_up" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("max_ramp_up", Float64, missing, false, "ThermalUnit", "ThermalUnit"), "max_ramp_down" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("max_ramp_down", Float64, missing, false, "ThermalUnit", "ThermalUnit"), "min_uptime" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("min_uptime", Float64, missing, false, "ThermalUnit", "ThermalUnit"), "max_uptime" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("max_uptime", Float64, missing, false, "ThermalUnit", "ThermalUnit"), "min_downtime" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("min_downtime", Float64, missing, false, "ThermalUnit", "ThermalUnit"), "max_startups" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("max_startups", Int64, missing, false, "ThermalUnit", "ThermalUnit"), "max_shutdowns" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("max_shutdowns", Int64, missing, false, "ThermalUnit", "ThermalUnit")…), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}("biddinggroup_id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("biddinggroup_id", Int64, missing, false, "ThermalUnit", "BiddingGroup", "id", "ThermalUnit"), "bus_id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("bus_id", Int64, missing, false, "ThermalUnit", "Bus", "id", "ThermalUnit")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}("existing" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Int64}("existing", Int64, missing, false, "parameters", "ThermalUnit", "ThermalUnit_time_series_parameters", ["date_time"], 1), "startup_cost" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("startup_cost", Float64, missing, false, "parameters", "ThermalUnit", "ThermalUnit_time_series_parameters", ["date_time"], 1), "min_generation" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("min_generation", Float64, missing, false, "parameters", "ThermalUnit", "ThermalUnit_time_series_parameters", ["date_time"], 1), "max_generation" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("max_generation", Float64, missing, false, "parameters", "ThermalUnit", "ThermalUnit_time_series_parameters", ["date_time"], 1), "om_cost" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("om_cost", Float64, missing, false, "parameters", "ThermalUnit", "ThermalUnit_time_series_parameters", ["date_time"], 1)), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}()), "DemandUnit" => PSRClassesInterface.PSRDatabaseSQLite.Collection("DemandUnit", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "DemandUnit", "DemandUnit"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, missing, true, "DemandUnit", "DemandUnit"), "demand_unit_type" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("demand_unit_type", Int64, 0, true, "DemandUnit", "DemandUnit"), "max_shift_up" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("max_shift_up", Float64, missing, false, "DemandUnit", "DemandUnit"), "max_shift_down" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("max_shift_down", Float64, missing, false, "DemandUnit", "DemandUnit"), "curtailment_cost" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("curtailment_cost", Float64, missing, false, "DemandUnit", "DemandUnit"), "max_curtailment" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Float64}("max_curtailment", Float64, missing, false, "DemandUnit", "DemandUnit")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}("bus_id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("bus_id", Int64, missing, false, "DemandUnit", "Bus", "id", "DemandUnit")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}("existing" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Int64}("existing", Int64, missing, false, "parameters", "DemandUnit", "DemandUnit_time_series_parameters", ["date_time"], 1)), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}("demand" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile{String}("demand", String, missing, true, "DemandUnit", "DemandUnit_time_series_files"), "elastic_demand_price" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile{String}("elastic_demand_price", String, missing, false, "DemandUnit", "DemandUnit_time_series_files"), "demand_window" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile{String}("demand_window", String, missing, false, "DemandUnit", "DemandUnit_time_series_files"))), "Zone" => PSRClassesInterface.PSRDatabaseSQLite.Collection("Zone", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "Zone", "Zone"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, missing, true, "Zone", "Zone")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}()), "Bus" => PSRClassesInterface.PSRDatabaseSQLite.Collection("Bus", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "Bus", "Bus"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, missing, true, "Bus", "Bus")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}("zone_id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("zone_id", Int64, missing, false, "Bus", "Zone", "id", "Bus")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}()), "DCLine" => PSRClassesInterface.PSRDatabaseSQLite.Collection("DCLine", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "DCLine", "DCLine"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, missing, true, "DCLine", "DCLine")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}("bus_from" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("bus_from", Int64, missing, false, "DCLine", "Bus", "from", "DCLine"), "bus_to" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("bus_to", Int64, missing, false, "DCLine", "Bus", "to", "DCLine")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}("existing" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Int64}("existing", Int64, missing, false, "parameters", "DCLine", "DCLine_time_series_parameters", ["date_time"], 1), "capacity_to" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("capacity_to", Float64, missing, false, "parameters", "DCLine", "DCLine_time_series_parameters", ["date_time"], 1), "capacity_from" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("capacity_from", Float64, missing, false, "parameters", "DCLine", "DCLine_time_series_parameters", ["date_time"], 1)), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}()), "Branch" => PSRClassesInterface.PSRDatabaseSQLite.Collection("Branch", OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter}("id" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("id", Int64, missing, false, "Branch", "Branch"), "label" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{String}("label", String, missing, true, "Branch", "Branch"), "line_model" => PSRClassesInterface.PSRDatabaseSQLite.ScalarParameter{Int64}("line_model", Int64, 0, true, "Branch", "Branch")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation}("bus_from" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("bus_from", Int64, missing, false, "Branch", "Bus", "from", "Branch"), "bus_to" => PSRClassesInterface.PSRDatabaseSQLite.ScalarRelation{Int64}("bus_to", Int64, missing, false, "Branch", "Bus", "to", "Branch")), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorParameter}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.VectorRelation}(), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeries}("existing" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Int64}("existing", Int64, missing, false, "parameters", "Branch", "Branch_time_series_parameters", ["date_time"], 1), "capacity" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("capacity", Float64, missing, false, "parameters", "Branch", "Branch_time_series_parameters", ["date_time"], 1), "reactance" => PSRClassesInterface.PSRDatabaseSQLite.TimeSeries{Float64}("reactance", Float64, missing, false, "parameters", "Branch", "Branch_time_series_parameters", ["date_time"], 1)), OrderedCollections.OrderedDict{String, PSRClassesInterface.PSRDatabaseSQLite.TimeSeriesFile}())…), false, PSRClassesInterface.PSRDatabaseSQLite.TimeController(Dict{Tuple{String, String}, PSRClassesInterface.PSRDatabaseSQLite.TimeControllerCache}(), Dict{String, Bool}()))
We will also update the inflow and demand time series files to have 2 periods.
IARA.link_time_series_to_file(
db,
"DemandUnit";
demand = "demands",
)
IARA.link_time_series_to_file(
db,
"HydroUnit";
inflow = "inflow",
)
;
IARA.close_study!(db)
Let's run the case.
IARA.train_min_cost(PATH_CYCLIC_2)
┌ Warning: Cycle duration in hours is 8760.0. This parameter is used to determine the node discount rate from the cycle discount rate.
│ Actual cycle duration is calculated considering the subproblem duration, number of nodes, and expected number of repeats per node. It's value is 48.0.
└ @ IARA ~/work/IARA.jl/IARA.jl/src/collections/configurations.jl:616
[ Info:
[ Info: Execution options
[ Info: Path: /home/runner/work/IARA.jl/IARA.jl/docs/build/tutorial/case_6_execution/cyclic_2
[ Info: Output path: /home/runner/work/IARA.jl/IARA.jl/docs/build/tutorial/case_6_execution/cyclic_2/outputs
[ Info: Run mode: TRAIN_MIN_COST
[ Info: Plot results: true
[ Info: periods: 2
[ Info: scenarios: 3
[ Info: subperiods: 1
[ Info:
[ Info: Collections
[ Info: HydroUnit: 1 element(s)
[ Info: ThermalUnit: 2 element(s)
[ Info: Zone: 1 element(s)
[ Info: Bus: 1 element(s)
[ Info: DemandUnit: 1 element(s)
[ Info: GaugingStation: 1 element(s)
[ Info:
[ Info: Time Series from external files
[ Info: inflow
[ Info: demand_unit
[ Info:
[ Info: Cuts file:
[ Info: No cuts file
[ Info:
-------------------------------------------------------------------
SDDP.jl (c) Oscar Dowson and contributors, 2017-24
-------------------------------------------------------------------
problem
nodes : 2
state variables : 1
scenarios : Inf
existing cuts : false
options
solver : serial mode
risk measure : SDDP.Expectation()
sampling scheme : SDDP.InSampleMonteCarlo
subproblem structure
VariableRef : [13, 13]
JuMP.AffExpr in MOI.EqualTo{Float64} : [4, 4]
JuMP.VariableRef in MOI.GreaterThan{Float64} : [10, 10]
JuMP.VariableRef in MOI.LessThan{Float64} : [6, 6]
JuMP.VariableRef in MOI.Parameter{Float64} : [2, 2]
numerical stability report
matrix range [1e+00, 1e+03]
objective range [1e-02, 9e+02]
bounds range [1e+01, 1e+03]
rhs range [0e+00, 0e+00]
-------------------------------------------------------------------
iteration simulation bound time (s) solves pid
-------------------------------------------------------------------
1 1.443720e+06 6.606018e+05 1.166525e+00 2127 1
2 8.054129e+06 6.820206e+05 1.425661e+02 178932 1
4 4.670309e+06 2.794802e+06 3.111692e+02 195226 1
-------------------------------------------------------------------
status : time_limit
total time (s) : 3.111692e+02
total solves : 195226
best bound : 2.794802e+06
simulation ci : 4.232902e+06 ± 2.813808e+06
numeric issues : 0
-------------------------------------------------------------------
[ Info: Running post-processing routines
[ Info: Building plots
Analyzing the results
Here's the graph of the final volume at each period
hydro_final_volume_all =
IARA.custom_plot(
hydro_final_volume_all,
IARA.PlotTimeSeriesMean;
title = "Reservoir Final Volume",
agents = ["Hydro1"],
period = 1:2,
)
With a cyclic policy graph, the decision-making process becomes more dynamic. The hydro unit is now planning with the expectation that the periods will repeat, creating an incentive to maintain a certain level of water in the reservoir.
Conclusion
Through these simulations, we observe significant differences between linear and cyclic policy graphs. In the 2-period linear setup, the model chooses an aggressive strategy at the end of the first year, since there is no incentive to conserve water for future periods. This short-term focus leads to a rapid depletion of the reservoir.
With 10 periods in the linear policy graph, the model's approach becomes more conservative, water levels are managed more carefully during the early years, reflecting a longer-term outlook. However, the reservoir is still emptied by the end of the fourth year, indicating a gradual shift toward resource depletion as the planning horizon progresses.
In contrast, the cyclic policy graph with 2 periods adds a dynamic element to the decision-making process. Here, the hydro unit balances the immediate need for power generation with the understanding that the periods will repeat, encouraging more sustainable water management across cycles.
This page was generated using Literate.jl.