HydroWaterFactorModel model tutorial

To follow along, you can download this tutorial as a Julia script (.jl) or Jupyter notebook (.ipynb).

Note

HydroPowerSimulations.jl is an extension library of PowerSimulations.jl for modeling hydro units. Users are encouraged to review the tutorial in PowerSimulations.jl on Running a Single-Step Problem before this tutorial.

Load packages

using PowerSystems
using PowerSimulations
using HydroPowerSimulations
using PowerSystemCaseBuilder
using Ipopt ## solver

Data

Note

PowerSystemCaseBuilder.jl is a helper library that makes it easier to reproduce examples in the documentation and tutorials. Normally you would pass your local files to create the system data instead of calling the function PowerSystemCaseBuilder.build_system.

sys = build_system(PSITestSystems, "c_sys5_hy_turbine_energy")
System
PropertyValue
Name
Description
System Units BaseSYSTEM_BASE
Base Power100.0
Base Frequency60.0
Num Components27
Static Components
TypeCount
ACBus5
Arc6
HydroReservoir1
HydroTurbine1
Line6
PowerLoad3
ThermalStandard5
Forecast Summary
owner_typeowner_categorynametime_series_typeinitial_timestampresolutioncounthorizonintervalwindow_count
StringStringStringStringStringDates.CompoundPeriodInt64Dates.CompoundPeriodDates.CompoundPeriodInt64
HydroReservoirComponenthydro_budgetDeterministic2024-01-01T00:00:001 hour11 day1 day2
HydroReservoirComponentinflowDeterministic2024-01-01T00:00:001 hour11 day1 day2
HydroReservoirComponentstorage_targetDeterministic2024-01-01T00:00:001 hour11 day1 day2
HydroTurbineComponentmax_active_powerDeterministic2024-01-01T00:00:001 hour11 day1 day2
PowerLoadComponentmax_active_powerDeterministic2024-01-01T00:00:001 hour31 day1 day2

With a single PowerSystems.HydroTurbine connected downstream to a PowerSystems.HydroReservoir:

reservoir = only(get_components(HydroReservoir, sys))
HydroReservoir: HydroEnergyReservoir__reservoir:
   name: HydroEnergyReservoir__reservoir
   available: true
   storage_level_limits: (min = 0.0, max = 5000.0)
   initial_level: 0.5
   spillage_limits: nothing
   inflow: 4.0
   outflow: 0.0
   level_targets: 1.0
   intake_elevation: 0.0
   head_to_volume_factor: InfrastructureSystems.LinearCurve(0.0, 0.0)
   upstream_turbines: 0-element Vector{PowerSystems.HydroUnit}
   downstream_turbines: 1-element Vector{PowerSystems.HydroUnit}
   upstream_reservoirs: 0-element Vector{PowerSystems.Device}
   operation_cost: 
   level_data_type: PowerSystems.ReservoirDataTypeModule.ReservoirDataType.ENERGY = 4
   ext: Dict{String, Any}()
   InfrastructureSystems.SystemUnitsSettings:
      base_value: 100.0
      unit_system: InfrastructureSystems.UnitSystemModule.UnitSystem.SYSTEM_BASE = 0
   has_supplemental_attributes: false
   has_time_series: true

Set the storage level limits using set_storage_level_limits!. Here the limits are set between $4000 and 6000 m^3$ .

set_storage_level_limits!(reservoir, (min = 4000, max = 6000))
(min = 4000, max = 6000)

Set the lower bound of reservoir volume using set_level_targets!. Here the level target is set at $0.9 \cdot 6000 = 5400 m^3$.

set_level_targets!(reservoir, 0.9)
0.9

Set the headtovolume factor to 1.0 using set_head_to_volume_factor!, since is an energy model and no conversion is needed.

set_head_to_volume_factor!(reservoir, LinearCurve(1.0))
InfrastructureSystems.LinearCurve (a type of InfrastructureSystems.InputOutputCurve) where function is: f(x) = 1.0 x + 0.0

Decision Model

Setting up the formulations based on PowerSimulations.jl:

template = ProblemTemplate(CopperPlatePowerModel)
set_device_model!(template, ThermalStandard, ThermalBasicDispatch)
set_device_model!(template, PowerLoad, StaticPowerLoad)

but, now we also include the HydroReservoir and HydroTurbine using HydroWaterFactorModel:

set_device_model!(template, HydroReservoir, HydroWaterFactorModel)
set_device_model!(template, HydroTurbine, HydroWaterFactorModel)

With the template properly set-up, we construct, build and solve the optimization problem:

model = DecisionModel(template, sys; optimizer = Ipopt.Optimizer)
build!(model; output_dir = mktempdir())
solve!(model)
InfrastructureSystems.Simulation.RunStatusModule.RunStatus.SUCCESSFULLY_FINALIZED = 0

Exploring Results

Results can be explored using:

results = OptimizationProblemResults(model)

Start: 2024-01-01T00:00:00

End: 2024-01-01T23:00:00

Resolution: 60 minutes

PowerSimulations Problem Auxiliary variables Results
HydroEnergyOutput__HydroTurbine
PowerSimulations Problem Expressions Results
FuelCostExpression__ThermalStandard
VOMCostExpression__ThermalStandard
ProductionCostExpression__ThermalStandard
ProductionCostExpression__HydroTurbine
ShutDownCostExpression__ThermalStandard
ActivePowerBalance__System
FixedCostExpression__ThermalStandard
StartUpCostExpression__ThermalStandard
PowerSimulations Problem Parameters Results
ActivePowerTimeSeriesParameter__PowerLoad
InflowTimeSeriesParameter__HydroReservoir
PowerSimulations Problem Variables Results
HydroReservoirVolumeVariable__HydroReservoir
ActivePowerVariable__ThermalStandard
WaterSpillageVariable__HydroReservoir
ActivePowerVariable__HydroTurbine

Use read_variable to read in the dispatch variable results for the hydro:

power =
    read_variable(
        results,
        "ActivePowerVariable__HydroTurbine";
        table_format = TableFormat.WIDE,
    )
14 rows omitted
DateTimeHydroEnergyReservoir_turbine
Dates.DateTimeFloat64?
2024-01-01T00:00:00700.0000069796481
2024-01-01T01:00:00692.1153451399834
2024-01-01T02:00:00670.2280854399376
2024-01-01T03:00:00643.44897543993
2024-01-01T04:00:00649.1417270399309
2024-01-01T05:00:00658.8662063399331
2024-01-01T06:00:00688.0143081399618
2024-01-01T07:00:00700.0000069796547
2024-01-01T08:00:00700.0000069796495
2024-01-01T09:00:00700.0000069796482

or the volume level of the reservoir

volume =
    read_variable(
        results,
        "HydroReservoirVolumeVariable__HydroReservoir";
        table_format = TableFormat.WIDE,
    )
14 rows omitted
DateTimeHydroEnergyReservoir__reservoir
Dates.DateTimeFloat64?
2024-01-01T00:00:004238.884628529651
2024-01-01T01:00:004942.327912266409
2024-01-01T02:00:004902.509727587584
2024-01-01T03:00:004906.116732850918
2024-01-01T04:00:004991.314427862555
2024-01-01T05:00:004876.110710237051
2024-01-01T06:00:004777.738351930663
2024-01-01T07:00:004958.217986682351
2024-01-01T08:00:004802.637219269302
2024-01-01T09:00:004894.1386504587435

Note that the final reservoir level is between the set level target and the maximum storage level.