Operation Problem with HydroPowerSimulations.jl

Note

HydroPowerSimulations.jl is an extension library of PowerSimulations.jl for modeling hydro units. Users are encouraged to review the single-step tutorial in PowerSimulations.jl before this tutorial.

Load packages

julia> using PowerSystems
julia> using PowerSimulations
julia> using HydroPowerSimulations
julia> using PowerSystemCaseBuilder
julia> using HiGHS # 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 build_system. For more details visit PowerSystemCaseBuilder README

julia> sys = build_system(PSITestSystems, "c_sys5_hy")┌ Info: Building new system c_sys5_hy from raw data
  sys_descriptor.raw_data = "/home/runner/.julia/artifacts/edcb5940e84a802a86ad4f2223214d33121ac044/PowerSystemsTestData-4.0.2/psy_data/data_5bus_pu.jl"
[ Info: Serialized time series data to /home/runner/.julia/packages/PowerSystemCaseBuilder/zW01F/data/serialized_system/4e67b70ea6977dbe21c7731d72cdc1494adf072a7f3f08d921db740cf264ce79/c_sys5_hy_time_series_storage.h5.
[ Info: Serialized System to /home/runner/.julia/packages/PowerSystemCaseBuilder/zW01F/data/serialized_system/4e67b70ea6977dbe21c7731d72cdc1494adf072a7f3f08d921db740cf264ce79/c_sys5_hy.json
[ Info: Serialized System metadata to /home/runner/.julia/packages/PowerSystemCaseBuilder/zW01F/data/serialized_system/4e67b70ea6977dbe21c7731d72cdc1494adf072a7f3f08d921db740cf264ce79/c_sys5_hy_metadata.json
              System
┌───────────────────┬─────────────┐
│ Property           Value       │
├───────────────────┼─────────────┤
│ Name              │             │
│ Description       │             │
│ System Units Base │ SYSTEM_BASE │
│ Base Power        │ 100.0       │
│ Base Frequency    │ 60.0        │
│ Num Components    │ 26          │
└───────────────────┴─────────────┘

     Static Components
┌─────────────────┬───────┐
│ Type             Count │
├─────────────────┼───────┤
│ ACBus           │ 5     │
│ Arc             │ 6     │
│ HydroDispatch   │ 1     │
│ Line            │ 6     │
│ PowerLoad       │ 3     │
│ ThermalStandard │ 5     │
└─────────────────┴───────┘

                                Forecast Summary
┌───────────────┬────────────────┬──────────────────┬──────────────────┬────────
│ owner_type     owner_category  name              time_series_type  initi ⋯
│ String         String          String            String            Strin ⋯
├───────────────┼────────────────┼──────────────────┼──────────────────┼────────
│ HydroDispatch │ Component      │ max_active_power │ Deterministic    │ 2024- ⋯
│ PowerLoad     │ Component      │ max_active_power │ Deterministic    │ 2024- ⋯
└───────────────┴────────────────┴──────────────────┴──────────────────┴────────
                                                               6 columns omitted

With a single PowerSystems.HydroDispatch:

julia> hy = only(get_components(HydroDispatch, sys))HydroDispatch: HydroDispatch:
   name: HydroDispatch
   available: true
   bus: ACBus: nodeB
   active_power: 0.0
   reactive_power: 0.0
   rating: 6.0
   prime_mover_type: PowerSystems.PrimeMoversModule.PrimeMovers.HY = 16
   active_power_limits: (min = 0.0, max = 6.0)
   reactive_power_limits: (min = 0.0, max = 6.0)
   ramp_limits: nothing
   time_limits: nothing
   base_power: 100.0
   status: false
   time_at_status: 10000.0
   operation_cost: PowerSystems.HydroGenerationCost composed of variable: InfrastructureSystems.CostCurve{InfrastructureSystems.LinearCurve}
   services: 0-element Vector{PowerSystems.Service}
   dynamic_injector: nothing
   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

Decision Model

Setting up the formulations based on PowerSimulations.jl:

julia> template = ProblemTemplate(PTDFPowerModel)                     Network Model
┌────────────────────┬─────────────────────────────────┐
│ Network Model      │ PowerSimulations.PTDFPowerModel │
│ Slacks             │ false                           │
│ PTDF               │ false                           │
│ Duals              │ None                            │
│ HVDC Network Model │ None                            │
└────────────────────┴─────────────────────────────────┘

            Device Models
┌─────────────┬─────────────┬────────┐
│ Device Type  Formulation  Slacks │
└─────────────┴─────────────┴────────┘
julia> set_device_model!(template, ThermalStandard, ThermalBasicDispatch)
julia> set_device_model!(template, PowerLoad, StaticPowerLoad)
julia> set_device_model!(template, Line, StaticBranch)

but, now we also include the hydro using HydroDispatchRunOfRiver:

julia> set_device_model!(template, HydroDispatch, HydroDispatchRunOfRiver)

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

julia> model = DecisionModel(template, sys; optimizer = HiGHS.Optimizer)[ Info: Overriding time_series_cache_size because time series is stored in memory
                     Network Model
┌────────────────────┬─────────────────────────────────┐
│ Network Model      │ PowerSimulations.PTDFPowerModel │
│ Slacks             │ false                           │
│ PTDF               │ false                           │
│ Duals              │ None                            │
│ HVDC Network Model │ None                            │
└────────────────────┴─────────────────────────────────┘

                                 Device Models
┌──────────────────────────────┬───────────────────────────────────────┬────────
│ Device Type                   Formulation                            Slack ⋯
├──────────────────────────────┼───────────────────────────────────────┼────────
│ PowerSystems.ThermalStandard │ PowerSimulations.ThermalBasicDispatch │ false ⋯
│ PowerSystems.PowerLoad       │ PowerSimulations.StaticPowerLoad      │ false ⋯
│ PowerSystems.HydroDispatch   │ HydroDispatchRunOfRiver               │ false ⋯
└──────────────────────────────┴───────────────────────────────────────┴────────
                                                                1 column omitted

                        Branch Models
┌───────────────────┬───────────────────────────────┬────────┐
│ Branch Type        Formulation                    Slacks │
├───────────────────┼───────────────────────────────┼────────┤
│ PowerSystems.Line │ PowerSimulations.StaticBranch │ false  │
└───────────────────┴───────────────────────────────┴────────┘
julia> build!(model; output_dir = mktempdir())InfrastructureSystems.Optimization.ModelBuildStatusModule.ModelBuildStatus.BUILT = 0
julia> solve!(model)InfrastructureSystems.Simulation.RunStatusModule.RunStatus.SUCCESSFULLY_FINALIZED = 0

Exploring Results

Results can be explored using:

julia> res = OptimizationProblemResults(model)Start: 2024-01-01T00:00:00
End: 2024-01-01T23:00:00
Resolution: 60 minutes

PowerSimulations Problem Auxiliary variables Results
┌──────────────────────────────────┐
│ HydroEnergyOutput__HydroDispatch │
└──────────────────────────────────┘

PowerSimulations Problem Expressions Results
┌───────────────────────────────────────────┐
│ PTDFBranchFlow__Line                      │
│ ActivePowerBalance__ACBus                 │
│ ProductionCostExpression__ThermalStandard │
│ ActivePowerBalance__System                │
│ ProductionCostExpression__HydroDispatch   │
└───────────────────────────────────────────┘

   PowerSimulations Problem Parameters Results
┌───────────────────────────────────────────────┐
│ ActivePowerTimeSeriesParameter__HydroDispatch │
│ ActivePowerTimeSeriesParameter__PowerLoad     │
└───────────────────────────────────────────────┘

PowerSimulations Problem Variables Results
┌──────────────────────────────────────┐
│ ActivePowerVariable__ThermalStandard │
│ ActivePowerVariable__HydroDispatch   │
└──────────────────────────────────────┘

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

julia> var = read_variable(res, "ActivePowerVariable__HydroDispatch")24×3 DataFrame
 Row  DateTime             name           value    
      DateTime             String         Float64  
─────┼──────────────────────────────────────────────
   1 │ 2024-01-01T00:00:00  HydroDispatch  188.58
   2 │ 2024-01-01T01:00:00  HydroDispatch  232.01
   3 │ 2024-01-01T02:00:00  HydroDispatch  137.149
   4 │ 2024-01-01T03:00:00  HydroDispatch  136.006
   5 │ 2024-01-01T04:00:00  HydroDispatch  133.72
   6 │ 2024-01-01T05:00:00  HydroDispatch   77.718
   7 │ 2024-01-01T06:00:00  HydroDispatch   86.8608
   8 │ 2024-01-01T07:00:00  HydroDispatch  219.439
  ⋮  │          ⋮                 ⋮           ⋮
  18 │ 2024-01-01T17:00:00  HydroDispatch  269.726
  19 │ 2024-01-01T18:00:00  HydroDispatch  378.303
  20 │ 2024-01-01T19:00:00  HydroDispatch  438.877
  21 │ 2024-01-01T20:00:00  HydroDispatch  466.307
  22 │ 2024-01-01T21:00:00  HydroDispatch  427.448
  23 │ 2024-01-01T22:00:00  HydroDispatch  468.593
  24 │ 2024-01-01T23:00:00  HydroDispatch  114.291
                                      9 rows omitted