From 3fb0c804a8acd533cc205e19b63b4a426fe92cfe Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 24 Apr 2023 16:23:32 -0600 Subject: [PATCH 001/370] remove code --- docs/make.jl | 1 - docs/src/formulation_library/General.md | 8 +- docs/src/formulation_library/HydroGen.md | 494 ------ src/PowerSimulations.jl | 8 - src/core/formulations.jl | 33 - .../hydrogeneration_constructor.jl | 1454 ----------------- .../devices/hydro_generation.jl | 814 --------- ...st_device_hydro_generation_constructors.jl | 642 -------- test/test_services_constructor.jl | 23 - 9 files changed, 4 insertions(+), 3473 deletions(-) delete mode 100644 docs/src/formulation_library/HydroGen.md delete mode 100644 src/devices_models/device_constructors/hydrogeneration_constructor.jl delete mode 100644 src/devices_models/devices/hydro_generation.jl delete mode 100644 test/test_device_hydro_generation_constructors.jl diff --git a/docs/make.jl b/docs/make.jl index acae742bbc..0759f5391c 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -30,7 +30,6 @@ pages = OrderedDict( "Formulation Library" => Any[ "General" => "formulation_library/General.md", "Thermal Generation" => "formulation_library/ThermalGen.md", - "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", diff --git a/docs/src/formulation_library/General.md b/docs/src/formulation_library/General.md index 26d11eefa1..8b69c0803a 100644 --- a/docs/src/formulation_library/General.md +++ b/docs/src/formulation_library/General.md @@ -29,7 +29,7 @@ using PowerSystems using DataFrames using Latexify combo_tables = [] -for t in [RenewableGen, ThermalGen, HydroGen, Storage, ElectricLoad] +for t in [RenewableGen, ThermalGen, ElectricLoad] combos = PowerSimulations.get_default_time_series_names(t, FixedOutput) combo_table = DataFrame( "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), @@ -84,9 +84,9 @@ PowerSimulations can represent variable costs using a variety of different metho ### Piecewise Linear `VariableCost` -`variable_cost <: Vector{Tuple{Float64, Float64}}`: creates a piecewise linear cost term in the objective function +`variable_cost <: Vector{Tuple{Float64, Float64}}`: creates a piecewise linear cost term in the objective function -TODO: add formulation +TODO: add formulation ___ @@ -96,7 +96,7 @@ Adds an objective function cost term according to: ```math \begin{aligned} -& \text{min} \sum_{t} \quad [E^{surplus}_t * C^{penalty} - E^{shortage}_t * C^{value}] +& \text{min} \sum_{t} \quad [E^{surplus}_t * C^{penalty} - E^{shortage}_t * C^{value}] \end{aligned} ``` diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md deleted file mode 100644 index fa9358547d..0000000000 --- a/docs/src/formulation_library/HydroGen.md +++ /dev/null @@ -1,494 +0,0 @@ -# `PowerSystems.HydroGen` Formulations - -Valid `DeviceModel`s for subtypes of `HydroGen` include the following: - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.generate_device_formulation_combinations() -filter!(x -> x["device_type"] <: HydroGen, combos) -combo_table = DataFrame( - "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], - "Device Type" => ["[$(c["device_type"])](https://nrel-siip.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], - "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], - ) -mdtable(combo_table, latex = false) -``` - ---- - -## `HydroDispatchRunOfRiver` - -```@docs -HydroDispatchRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroDispatchRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} -\end{aligned} -``` - ---- - -## `HydroDispatchPumpedStorage` - -```@docs -HydroDispatchPumpedStorage -``` - -**Variables:** - -- [`ActivePowerInVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `-1 * PowerSystems.get_active_power(device)` -- [`ActivePowerOutVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`EnergyVariableUp`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device).up` -- [`EnergyVariableDown`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device).down` -- [`WaterSpillageVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`EnergyOutput`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`ReservationVariable`](@ref): - - only included if `DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage; attributes = Dict(reservation => true))` - - Bounds: {0, 1} - - Default initial value: 1 - -**Static Parameters:** - -- ``Pg^\text{out, max}`` = `map(x -> x.max - x.min, PowerSystems.get_active_power_limits(device))` -- ``Pg^\text{in, max}`` = `map(x -> x.max - x.min, PowerSystems.get_active_power_limits_pump(device))` -- ``Eg^\text{up, max}`` = `PowerSystems.get_storage_capacity(device).up` -- ``Eg^\text{down, max}`` = `PowerSystems.get_storage_capacity(device).down` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroPumpedStorage, HydroDispatchPumpedStorage) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg^{out}``. - -**Expressions:** - -Adds ``Pg`` term(s) to the active power balance expression(s) created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& E^{up}_{t+1} = E^{up}_t + (InflowTimeSeriesParameter_t - S_t - Pg^{out}_t + Pg^{in}_t) \cdot \Delta T \\ -& E^{down}_{t+1} = E^{down}_t + (S_t - OutflowTimeSeriesParameter_t + Pg^{out}_t - Pg^{in}_t) \cdot \Delta T \\ -& Pg^{in}_t - r * Pg^\text{in, max} \le Pg^\text{in, max} \\ -& Pg^{out}_t + r * Pg^\text{out, max} \le Pg^\text{out, max} \\ -& E^{up}_t \le E^{up, max} -& E^{down}_t \le E^{down, max} -\end{aligned} -``` - ---- - -## `HydroDispatchReservoirBudget` - -```@docs -HydroDispatchReservoirBudget -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - TODO - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroDispatchReservoirBudget) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg^\text{min} \le Pg_t \le Pg^\text{max} \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} \\ -& \sum_{t = 1}^N(Pg_t) \cdot \Delta T \le \sum_{t = 1}^N(EnergyBudgetTimeSeriesParameter_t) \cdot \Delta T -\end{aligned} -``` - ---- - -## `HydroDispatchReservoirStorage` - -```@docs -HydroDispatchReservoirStorage -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`EnergyVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device)` -- [`WaterSpillageVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`EnergyShortageVariable`](@ref): - - Bounds: [ , 0.0] - - Default initial value: 0.0 -- [`EnergySurplusVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` -- ``Eg^\text{max}`` = `PowerSystems.get_storage_capacity(device)` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroDispatchReservoirStorage) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. -TODO: add slack terms - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& E_{t+1} = E_t + (InflowTimeSeriesParameter_t - S_t - Pg_t) \cdot \Delta T \\ -& E_t - E^{surplus}_t + E^{shortage}_t = EnergyTargetTimeSeriesParameter_t \\ -& Pg^\text{min} \le Pg_t \le Pg^\text{max} \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} -\end{aligned} -``` - ---- - -## `HydroCommitmentReservoirBudget` - -```@docs -HydroCommitmentReservoirBudget -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - TODO - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroCommitmentReservoirBudget) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& \sum_{t = 1}^N P_t \cdot \Delta T \le E^\text{budget} \\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` - ---- - -## `HydroCommitmentReservoirStorage` - -```@docs -HydroCommitmentReservoirStorage -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`EnergyVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device)` -- [`WaterSpillageVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`EnergyShortageVariable`](@ref): - - Bounds: [ , 0.0] - - Default initial value: 0.0 -- [`EnergySurplusVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` -- ``Eg^\text{max}`` = `PowerSystems.get_storage_capacity(device)` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroCommitmentReservoirStorage) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``, -and objective function terms for [StorageManagementCost](@ref). - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& E_{t+1} = E_t + (InflowTimeSeriesParameter_t - S_t - Pg_t) \cdot \Delta T \\ -& E_t - E^{surplus}_t + E^{shortage}_t = EnergyTargetTimeSeriesParameter_t \\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` - ---- - -## `HydroCommitmentRunOfRiver` - -```@docs -HydroCommitmentRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroCommitmentRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg_t \le Pg^\text{max}\\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index bc76304f08..9c41ad342c 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -51,14 +51,6 @@ export PowerLoadDispatch ######## Renewable Formulations ######## export RenewableFullDispatch export RenewableConstantPowerFactor -######## Hydro Formulations ######## -export HydroDispatchRunOfRiver -export HydroDispatchReservoirBudget -export HydroDispatchReservoirStorage -export HydroCommitmentRunOfRiver -export HydroCommitmentReservoirBudget -export HydroCommitmentReservoirStorage -export HydroDispatchPumpedStorage ######## Thermal Formulations ######## export ThermalStandardUnitCommitment diff --git a/src/core/formulations.jl b/src/core/formulations.jl index dedffc553a..948289a0e0 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -74,45 +74,12 @@ struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end ############################ Hydro Generation Formulations ################################# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end -abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end -abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end -abstract type AbstractHydroReservoirFormulation <: AbstractHydroDispatchFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end -""" -Formulation type to add injection variables constrained by total energy production budget defined with a time series for `HydroGen` -""" -struct HydroDispatchReservoirBudget <: AbstractHydroReservoirFormulation end - -""" -Formulation type to constrain hydropower production with a representation of the energy storage capacity and water inflow time series of a reservoir for `HydroGen` -""" -struct HydroDispatchReservoirStorage <: AbstractHydroReservoirFormulation end - -""" -Formulation type to constrain energy production from pumped storage with a representation of the energy storage capacity of upper and lower reservoirs and water inflow time series of upper reservoir and outflow time series of lower reservoir for `HydroPumpedStorage` -""" -struct HydroDispatchPumpedStorage <: AbstractHydroReservoirFormulation end - -""" -Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` -""" -struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end - -""" -Formulation type to add commitment and injection variables constrained by total energy production budget defined with a time series for `HydroGen` -""" -struct HydroCommitmentReservoirBudget <: AbstractHydroUnitCommitment end - -""" -Formulation type to constrain hydropower production with unit commitment variables and a representation of the energy storage capacity and water inflow time series of a reservoir for `HydroGen` -""" -struct HydroCommitmentReservoirStorage <: AbstractHydroUnitCommitment end - ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end struct ReserveLimitedRegulation <: AbstractRegulationFormulation end diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl deleted file mode 100644 index b27fb216ed..0000000000 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ /dev/null @@ -1,1454 +0,0 @@ -""" -Construct model for HydroGen with FixedOutput Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -function construct_device!( - ::OptimizationContainer, - ::PSY.System, - ::ModelConstructStage, - ::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - # FixedOutput doesn't add any constraints to the model. This function covers - # AbstractPowerModel and AbtractActivePowerModel - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} - devices = get_available_components(H, sys) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -""" -Construct model for HydroGen with RunOfRiver Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = get_available_components(H, sys) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = get_available_components(H, sys) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with RunOfRiver Dispatch Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = get_available_components(H, sys) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = get_available_components(H, sys) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirBudget Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirBudget()) - add_variables!( - container, - ReactivePowerVariable, - devices, - HydroDispatchReservoirBudget(), - ) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirBudget()) - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirBudget Dispatch Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = get_available_components(H, sys) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirBudget()) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirBudget()) - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = get_available_components(H, sys) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with ReservoirStorage Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirStorage()) - add_variables!( - container, - ReactivePowerVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!(container, EnergyVariable, devices, HydroDispatchReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirStorage()) - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroDispatchReservoirStorage(), - InitialEnergyLevel(), - ) - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirStorage Dispatch Formulation -with only Active Power -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = get_available_components(H, sys) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirStorage()) - add_variables!(container, EnergyVariable, devices, HydroDispatchReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirStorage()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = get_available_components(H, sys) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroDispatchReservoirStorage(), - InitialEnergyLevel(), - ) - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = get_available_components(H, sys) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = get_available_components(H, sys) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirBudget Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentReservoirBudget, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentReservoirBudget, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with ReservoirBudget Commitment Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentReservoirBudget, - S <: PM.AbstractActivePowerModel, -} - devices = get_available_components(H, sys) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentReservoirBudget, - S <: PM.AbstractActivePowerModel, -} - devices = get_available_components(H, sys) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirStorage Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) - - add_variables!( - container, - ActivePowerVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - ReactivePowerVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!(container, OnVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!(container, EnergyVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!(container, EnergyOutput, devices, HydroCommitmentReservoirStorage()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroCommitmentReservoirStorage(), - InitialEnergyLevel(), - ) - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with ReservoirStorage Dispatch Formulation -with only Active Power -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = get_available_components(H, sys) - - add_variables!( - container, - ActivePowerVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!(container, OnVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!(container, EnergyVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_variables!(container, EnergyOutput, devices, HydroCommitmentReservoirStorage()) - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = get_available_components(H, sys) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroCommitmentReservoirStorage(), - InitialEnergyLevel(), - ) - - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroPumpedStorage with PumpedStorage Dispatch Formulation -with only Active Power -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchPumpedStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroPumpedStorage, S <: PM.AbstractActivePowerModel} - devices = get_available_components(H, sys) - - add_variables!(container, ActivePowerInVariable, devices, HydroDispatchPumpedStorage()) - add_variables!(container, ActivePowerOutVariable, devices, HydroDispatchPumpedStorage()) - add_variables!(container, EnergyVariableUp, devices, HydroDispatchPumpedStorage()) - add_variables!(container, EnergyVariableDown, devices, HydroDispatchPumpedStorage()) - add_variables!(container, WaterSpillageVariable, devices, HydroDispatchPumpedStorage()) - add_variables!(container, EnergyOutput, devices, HydroDispatchPumpedStorage()) - if get_attribute(model, "reservation") - add_variables!( - container, - ReservationVariable, - devices, - HydroDispatchPumpedStorage(), - ) - end - - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - add_parameters!(container, OutflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerInVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ReserveRangeExpressionLB, devices, model) - add_expressions!(container, ReserveRangeExpressionUB, devices, model) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchPumpedStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroPumpedStorage, S <: PM.AbstractActivePowerModel} - devices = get_available_components(H, sys) - - add_constraints!( - container, - OutputActivePowerVariableLimitsConstraint, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - InputActivePowerVariableLimitsConstraint, - ActivePowerInVariable, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroDispatchPumpedStorage(), - InitialEnergyLevelUp(), - ) - add_initial_condition!( - container, - devices, - HydroDispatchPumpedStorage(), - InitialEnergyLevelDown(), - ) - - # Energy Balanace limits - add_constraints!(container, EnergyCapacityUpConstraint, devices, model, network_model) - add_constraints!(container, EnergyCapacityDownConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl deleted file mode 100644 index ce935d0325..0000000000 --- a/src/devices_models/devices/hydro_generation.jl +++ /dev/null @@ -1,814 +0,0 @@ -#! format: off -requires_initialization(::AbstractHydroFormulation) = false -requires_initialization(::AbstractHydroUnitCommitment) = true - -get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroPumpedStorage}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ReserveRangeExpressionUB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroPumpedStorage}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ReserveRangeExpressionLB - -########################### ActivePowerVariable, HydroGen ################################# -get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 -get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max - -############## ActivePowerVariable, HydroDispatchRunOfRiver #################### -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 - -############## ReactivePowerVariable, HydroGen #################### -get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min -get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max - -############## EnergyVariable, HydroGen #################### -get_variable_binary(::EnergyVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(pv::EnergyVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d) -get_variable_lower_bound(::EnergyVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) - -########################### EnergyVariableUp, HydroGen ################################# -get_variable_binary(::EnergyVariableUp, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(pv::EnergyVariableUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).up -get_variable_lower_bound(::EnergyVariableUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyVariableUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d).up - -########################### EnergyVariableDown, HydroGen ################################# -get_variable_binary(::EnergyVariableDown, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::EnergyVariableDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).down -get_variable_lower_bound(::EnergyVariableDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyVariableDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d).down - -########################### ActivePowerInVariable, HydroGen ################################# -get_variable_binary(::ActivePowerInVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::ActivePowerInVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::ActivePowerInVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = nothing -get_variable_multiplier(::ActivePowerInVariable, d::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = -1.0 - -########################### ActivePowerOutVariable, HydroGen ################################# -get_variable_binary(::ActivePowerOutVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::ActivePowerOutVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::ActivePowerOutVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = nothing -get_variable_multiplier(::ActivePowerOutVariable, d::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 - -############## OnVariable, HydroGen #################### -get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true -get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 - -############## WaterSpillageVariable, HydroGen #################### -get_variable_binary(::WaterSpillageVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::WaterSpillageVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 - -############## ReservationVariable, HydroGen #################### -get_variable_binary(::ReservationVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true -get_variable_binary(::ReservationVariable, ::Type{<:PSY.HydroPumpedStorage}, ::AbstractHydroFormulation) = true - -############## EnergyShortageVariable, HydroGen #################### -get_variable_binary(::EnergyShortageVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::EnergyShortageVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyShortageVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) -get_variable_upper_bound(::EnergyShortageVariable, d::PSY.HydroPumpedStorage, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d).up -############## EnergySurplusVariable, HydroGen #################### -get_variable_binary(::EnergySurplusVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_upper_bound(::EnergySurplusVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_lower_bound(::EnergySurplusVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = - PSY.get_storage_capacity(d) -get_variable_lower_bound(::EnergySurplusVariable, d::PSY.HydroPumpedStorage, ::AbstractHydroFormulation) = - PSY.get_storage_capacity(d).up -########################### Parameter related set functions ################################ -get_multiplier_value(::EnergyBudgetTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::EnergyBudgetTimeSeriesParameter, d::PSY.HydroEnergyReservoir, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) -get_multiplier_value(::EnergyTargetTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) -get_multiplier_value(::InflowTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_inflow(d) * PSY.get_conversion_factor(d) -get_multiplier_value(::OutflowTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_outflow(d) * PSY.get_conversion_factor(d) -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) - -get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min - -#################### Initial Conditions for models ############### -initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) -initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() -initial_condition_default(::InitialEnergyLevel, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d) -initial_condition_variable(::InitialEnergyLevel, d::PSY.HydroGen, ::AbstractHydroFormulation) = EnergyVariable() -initial_condition_default(::InitialEnergyLevelUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).up -initial_condition_variable(::InitialEnergyLevelUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = EnergyVariableUp() -initial_condition_default(::InitialEnergyLevelDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).down -initial_condition_variable(::InitialEnergyLevelDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = EnergyVariableDown() -initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 -initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) -initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() - -########################Objective Function################################################## -proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 -proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_surplus_cost(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_shortage_cost(cost) - -objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::EnergySurplusVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_NEGATIVE -objective_function_multiplier(::EnergyShortageVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE - -sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE -sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE - -variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 -variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) -variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) - -#! format: on - -function get_initial_conditions_device_model( - ::OperationModel, - model::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroEnergyReservoir} - return model -end - -function get_initial_conditions_device_model( - ::OperationModel, - ::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroDispatch} - return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) -end - -function get_initial_conditions_device_model( - ::OperationModel, - ::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroPumpedStorage} - return DeviceModel(PSY.HydroPumpedStorage, HydroDispatchPumpedStorage) -end - -function get_default_time_series_names( - ::Type{<:PSY.HydroGen}, - ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - ActivePowerTimeSeriesParameter => "max_active_power", - ReactivePowerTimeSeriesParameter => "max_active_power", - ) -end - -function get_default_time_series_names( - ::Type{PSY.HydroEnergyReservoir}, - ::Type{<:Union{HydroCommitmentReservoirBudget, HydroDispatchReservoirBudget}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - EnergyBudgetTimeSeriesParameter => "hydro_budget", - ) -end - -function get_default_time_series_names( - ::Type{PSY.HydroEnergyReservoir}, - ::Type{<:Union{HydroDispatchReservoirStorage, HydroCommitmentReservoirStorage}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - EnergyTargetTimeSeriesParameter => "storage_target", - InflowTimeSeriesParameter => "inflow", - ) -end - -function get_default_time_series_names( - ::Type{PSY.HydroPumpedStorage}, - ::Type{<:HydroDispatchPumpedStorage}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - InflowTimeSeriesParameter => "inflow", - OutflowTimeSeriesParameter => "outflow", - ) -end - -function get_default_attributes( - ::Type{T}, - ::Type{D}, -) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} - return Dict{String, Any}("reservation" => false) -end - -function get_default_attributes( - ::Type{PSY.HydroPumpedStorage}, - ::Type{HydroDispatchPumpedStorage}, -) - return Dict{String, Any}("reservation" => true) -end - -""" -Time series constraints -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:RangeConstraintLBExpressions}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -""" -Add semicontinuous range constraints for Hydro Unit Commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -""" -Min and max reactive Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ReactivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_reactive_power_limits(x) -end - -""" -Min and max active Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_active_power_limits(x) -end - -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchRunOfRiver}, -) - return (min = 0.0, max = PSY.get_max_active_power(x)) -end - -""" -Add power variable limits constraints for hydro unit commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -""" -Add power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroGen, - W <: AbstractHydroDispatchFormulation, - X <: PM.AbstractPowerModel, -} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -""" -Add input power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{InputActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroReservoirFormulation, - X <: PM.AbstractPowerModel, -} - if get_attribute(model, "reservation") - add_reserve_range_constraints!(container, T, U, devices, model, X) - else - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - end - return -end - -""" -Add output power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroReservoirFormulation, - X <: PM.AbstractPowerModel, -} - if get_attribute(model, "reservation") - add_reserve_range_constraints!(container, T, U, devices, model, X) - else - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - end - return -end - -""" -Min and max output active power variable limits for hydro dispatch pumped storage -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:OutputActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchPumpedStorage}, -) - return PSY.get_active_power_limits(x) -end - -""" -Min and max input active power variable limits for hydro dispatch pumped storage -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:InputActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchPumpedStorage}, -) - return PSY.get_active_power_limits_pump(x) -end - -######################## Energy balance constraints ############################ - -""" -This function defines the constraints for the water level (or state of charge) -for the Hydro Reservoir. -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyBalanceConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroEnergyReservoir, - W <: AbstractHydroFormulation, - X <: PM.AbstractPowerModel, -} - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - names = [PSY.get_name(x) for x in devices] - initial_conditions = get_initial_condition(container, InitialEnergyLevel(), V) - energy_var = get_variable(container, EnergyVariable(), V) - power_var = get_variable(container, ActivePowerVariable(), V) - spillage_var = get_variable(container, WaterSpillageVariable(), V) - - constraint = add_constraints_container!( - container, - EnergyBalanceConstraint(), - V, - names, - time_steps, - ) - param_container = get_parameter(container, InflowTimeSeriesParameter(), V) - multiplier = get_parameter_multiplier_array(container, InflowTimeSeriesParameter(), V) - - for ic in initial_conditions - device = get_component(ic) - name = PSY.get_name(device) - param = get_parameter_column_values(param_container, name) - constraint[name, 1] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, 1] == - get_value(ic) - power_var[name, 1] * fraction_of_hour - - spillage_var[name, 1] * fraction_of_hour + param[1] * multiplier[name, 1] - ) - - for t in time_steps[2:end] - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, t] == - energy_var[name, t - 1] + param[t] * multiplier[name, t] - - power_var[name, t] * fraction_of_hour - - spillage_var[name, t] * fraction_of_hour - ) - end - end - return -end - -""" -This function defines the constraints for the water level (or state of charge) -for the HydroPumpedStorage. -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyCapacityUpConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroFormulation, - X <: PM.AbstractPowerModel, -} - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - names = [PSY.get_name(x) for x in devices] - initial_conditions = get_initial_condition(container, InitialEnergyLevelUp(), V) - - energy_var = get_variable(container, EnergyVariableUp(), V) - powerin_var = get_variable(container, ActivePowerInVariable(), V) - powerout_var = get_variable(container, ActivePowerOutVariable(), V) - spillage_var = get_variable(container, WaterSpillageVariable(), V) - - constraint = add_constraints_container!( - container, - EnergyCapacityUpConstraint(), - V, - names, - time_steps, - ) - param_container = get_parameter(container, InflowTimeSeriesParameter(), V) - multiplier = get_multiplier_array(param_container) - - for ic in initial_conditions - device = get_component(ic) - efficiency = PSY.get_pump_efficiency(device) - name = PSY.get_name(device) - constraint[name, 1] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, 1] == - get_value(ic) + - ( - powerin_var[name, 1] - - (spillage_var[name, 1] + powerout_var[name, 1]) / efficiency - ) * fraction_of_hour + - get_parameter_column_refs(param_container, name)[1] * multiplier[name, 1] - ) - - for t in time_steps[2:end] - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, t] == - energy_var[name, t - 1] + - get_parameter_column_refs(param_container, name)[t] * multiplier[name, t] + - ( - powerin_var[name, 1] - - (powerout_var[name, t] + spillage_var[name, t]) / efficiency - ) * fraction_of_hour - ) - end - end - return -end - -""" -Add energy capacity down constraints for hydro pumped storage -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyCapacityDownConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroFormulation, - X <: PM.AbstractPowerModel, -} - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - names = [PSY.get_name(x) for x in devices] - initial_conditions = get_initial_condition(container, InitialEnergyLevelDown(), V) - - energy_var = get_variable(container, EnergyVariableDown(), V) - powerin_var = get_variable(container, ActivePowerInVariable(), V) - powerout_var = get_variable(container, ActivePowerOutVariable(), V) - spillage_var = get_variable(container, WaterSpillageVariable(), V) - - constraint = add_constraints_container!( - container, - EnergyCapacityDownConstraint(), - V, - names, - time_steps, - ) - - param_container = get_parameter(container, OutflowTimeSeriesParameter(), V) - multiplier = get_multiplier_array(param_container) - - for ic in initial_conditions - device = get_component(ic) - efficiency = PSY.get_pump_efficiency(device) - name = PSY.get_name(device) - param = get_parameter_column_refs(param_container, name) - constraint[name, 1] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, 1] == - get_value(ic) - - ( - spillage_var[name, 1] + powerout_var[name, 1] - - powerin_var[name, 1] / efficiency - ) * fraction_of_hour - param[1] * multiplier[name, 1] - ) - - for t in time_steps[2:end] - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, t] == - energy_var[name, t - 1] - param[t] * multiplier[name, t] + - ( - powerout_var[name, t] - powerin_var[name, t] / efficiency + - spillage_var[name, t] - ) * fraction_of_hour - ) - end - end - return -end - -""" -Add energy target constraints for hydro gen -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyTargetConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroFormulation, X <: PM.AbstractPowerModel} - time_steps = get_time_steps(container) - set_name = [PSY.get_name(d) for d in devices] - constraint = add_constraints_container!( - container, - EnergyTargetConstraint(), - V, - set_name, - time_steps, - ) - - e_var = get_variable(container, EnergyVariable(), V) - shortage_var = get_variable(container, EnergyShortageVariable(), V) - surplus_var = get_variable(container, EnergySurplusVariable(), V) - param_container = get_parameter(container, EnergyTargetTimeSeriesParameter(), V) - multiplier = - get_parameter_multiplier_array(container, EnergyTargetTimeSeriesParameter(), V) - - for d in devices - name = PSY.get_name(d) - cost_data = PSY.get_operation_cost(d) - if isa(cost_data, PSY.StorageManagementCost) - shortage_cost = PSY.get_energy_shortage_cost(cost_data) - else - @debug "Data for device $name doesn't contain shortage costs" - shortage_cost = 0.0 - end - - if shortage_cost == 0.0 - @warn( - "Device $name has energy shortage cost set to 0.0, as a result the model will turnoff the EnergyShortageVariable to avoid infeasible/unbounded problem." - ) - JuMP.delete_upper_bound.(shortage_var[name, :]) - JuMP.set_upper_bound.(shortage_var[name, :], 0.0) - end - param = get_parameter_column_values(param_container, name) - for t in time_steps - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - e_var[name, t] + shortage_var[name, t] + surplus_var[name, t] == - multiplier[name, t] * param[t] - ) - end - end - return -end - -##################################### Water/Energy Budget Constraint ############################ -""" -This function define the budget constraint for the -active power budget formulation. - -`` sum(P[t]) <= Budget `` -""" - -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyBudgetConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroFormulation, X <: PM.AbstractPowerModel} - time_steps = get_time_steps(container) - set_name = [PSY.get_name(d) for d in devices] - constraint = - add_constraints_container!(container, EnergyBudgetConstraint(), V, set_name) - - variable_out = get_variable(container, ActivePowerVariable(), V) - param_container = get_parameter(container, EnergyBudgetTimeSeriesParameter(), V) - multiplier = get_multiplier_array(param_container) - - for d in devices - name = PSY.get_name(d) - param = get_parameter_column_values(param_container, name) - constraint[name] = JuMP.@constraint( - container.JuMPmodel, - sum([variable_out[name, t] for t in time_steps]) <= - sum([multiplier[name, t] * param[t] for t in time_steps]) - ) - end - return -end - -##################################### Auxillary Variables ############################ - -function calculate_aux_variable_value!( - container::OptimizationContainer, - ::AuxVarKey{EnergyOutput, T}, - system::PSY.System, -) where {T <: PSY.HydroGen} - devices = get_available_components(T, system) - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - p_variable_results = get_variable(container, ActivePowerVariable(), T) - aux_variable_container = get_aux_variable(container, EnergyOutput(), T) - for d in devices, t in time_steps - name = PSY.get_name(d) - aux_variable_container[name, t] = - jump_value(p_variable_results[name, t]) * fraction_of_hour - end - - return -end - -function calculate_aux_variable_value!( - container::OptimizationContainer, - ::AuxVarKey{EnergyOutput, T}, - system::PSY.System, -) where {T <: PSY.HydroPumpedStorage} - devices = get_available_components(T, system) - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - p_variable_results = get_variable(container, ActivePowerOutVariable(), T) - aux_variable_container = get_aux_variable(container, EnergyOutput(), T) - for d in devices, t in time_steps - name = PSY.get_name(d) - aux_variable_container[name, t] = - jump_value(p_variable_results[name, t]) * fraction_of_hour - end - - return -end - -##################################### Hydro generation cost ############################ -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, OnVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{PSY.HydroPumpedStorage}, - ::DeviceModel{PSY.HydroPumpedStorage, T}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: HydroDispatchPumpedStorage} - add_variable_cost!(container, ActivePowerOutVariable(), devices, T()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where { - T <: PSY.HydroPumpedStorage, - U <: Union{HydroDispatchReservoirStorage, HydroDispatchReservoirBudget}, -} - add_variable_cost!(container, ActivePowerOutVariable(), devices, U()) - add_proportional_cost!(container, EnergySurplusVariable(), devices, U()) - add_proportional_cost!(container, EnergyShortageVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroEnergyReservoir, U <: HydroDispatchReservoirStorage} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, EnergySurplusVariable(), devices, U()) - add_proportional_cost!(container, EnergyShortageVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroEnergyReservoir, U <: HydroCommitmentReservoirStorage} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, EnergySurplusVariable(), devices, U()) - add_proportional_cost!(container, EnergyShortageVariable(), devices, U()) - return -end diff --git a/test/test_device_hydro_generation_constructors.jl b/test/test_device_hydro_generation_constructors.jl deleted file mode 100644 index ef37a71eab..0000000000 --- a/test/test_device_hydro_generation_constructors.jl +++ /dev/null @@ -1,642 +0,0 @@ -################################### -###### FIXED OUTPUT TESTS ######### -################################### - -@testset "Hydro DCPLossLess FixedOutput" begin - device_model = DeviceModel(HydroDispatch, FixedOutput) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with FixedOutput formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, FixedOutput) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -### RUN OF RIVER DISPATCH TESTS ### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -#### RUN OF RIVER COMMIT TESTS #### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -#### RESERVOIR BUDGET DISPATCH TESTS #### -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 25, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 49, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -#### PUMPED STORAGE DISPATCH TESTS #### -######################################### - -@testset "Hydro DCPLossLess HydroPumpedStorage with HydroDispatchPumpedStorage Formulations" begin - device_model = DeviceModel( - HydroPumpedStorage, - HydroDispatchPumpedStorage; - attributes = Dict{String, Any}("reservation" => false), - ) - c_sys5_phes_ed = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_phes_ed) - mock_construct_device!(model, device_model) - moi_tests(model, 60, 0, 24, 24, 24, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroPumpedStorage with HydroDispatchPumpedStorage with Reservation Formulations" begin - device_model = DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage) - c_sys5_phes_ed = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_phes_ed) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 24, 24, 24, true) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -### RESERVOIR BUDGET COMMITMENT TESTS ### -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 25, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 49, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -### RESERVOIR STORAGE DISPATCH TESTS #### -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 120, 0, 24, 24, 48, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPLossLess HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 144, 0, 48, 48, 48, false) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -### RESERVOIR STORAGE COMMITMENT TESTS ## -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 144, 0, 24, 24, 48, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPLossLess HydroEnergyReservoir with HydroCommitmentReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 168, 0, 48, 48, 48, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Solving ED Hydro System using Dispatch Run of River" begin - sys = PSB.build_system(PSITestSystems, "c_sys5_hy") - networks = [ACPPowerModel, DCPPowerModel] - - test_results = Dict{Any, Float64}(ACPPowerModel => 177526.0, DCPPowerModel => 175521.0) - - for net in networks - @testset "HydroRoR ED model $(net)" begin - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroDispatch, HydroDispatchRunOfRiver) - ED = DecisionModel( - EconomicDispatchProblem, - template, - sys; - optimizer = ipopt_optimizer, - ) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == - PSI.BuildStatus.BUILT - psi_checksolve_test( - ED, - [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], - test_results[net], - 1000, - ) - end - end -end - -@testset "Solving ED Hydro System using Commitment Run of River" begin - sys = PSB.build_system(PSITestSystems, "c_sys5_hy") - net = DCPPowerModel - - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroDispatch, HydroCommitmentRunOfRiver) - - @testset "HydroRoR ED model $(net)" begin - ED = DecisionModel(UnitCommitmentProblem, template, sys; optimizer = GLPK_optimizer) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - psi_checksolve_test(ED, [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], 175521.0, 1000) - end -end - -@testset "Solving ED Hydro System using Dispatch with Reservoir" begin - systems = [ - PSB.build_system(PSITestSystems, "c_sys5_hyd"), - PSB.build_system(PSITestSystems, "c_sys5_hyd_ems"), - ] - networks = [ACPPowerModel, DCPPowerModel] - models = [HydroDispatchReservoirBudget, HydroDispatchReservoirStorage] - test_results = Dict{Any, Float64}( - (ACPPowerModel, HydroDispatchReservoirBudget) => 33423.0, - (DCPPowerModel, HydroDispatchReservoirBudget) => 33042.0, - (ACPPowerModel, HydroDispatchReservoirStorage) => 232497.0, - (DCPPowerModel, HydroDispatchReservoirStorage) => 230153.0, - ) - - for net in networks, (mod, sys) in zip(models, systems) - @testset "$(mod) ED model on $(net)" begin - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroEnergyReservoir, mod) - - ED = DecisionModel( - EconomicDispatchProblem, - template, - sys; - optimizer = ipopt_optimizer, - ) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == - PSI.BuildStatus.BUILT - psi_checksolve_test( - ED, - [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], - test_results[(net, mod)], - 10000, - ) - end - end -end - -@testset "Solving ED Hydro System using Commitment with Reservoir" begin - systems = [ - PSB.build_system(PSITestSystems, "c_sys5_hyd"), - PSB.build_system(PSITestSystems, "c_sys5_hyd_ems"), - ] - net = DCPPowerModel - models = [HydroCommitmentReservoirBudget, HydroCommitmentReservoirStorage] - test_results = Dict{Any, Float64}( - HydroCommitmentReservoirBudget => 33042.0, - HydroCommitmentReservoirStorage => 230153.0, - ) - - for (mod, sys) in zip(models, systems) - @testset "$(mod) ED model on $(net) and use_parameters = true" begin - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroEnergyReservoir, mod) - - ED = DecisionModel( - UnitCommitmentProblem, - template, - sys; - optimizer = GLPK_optimizer, - ) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == - PSI.BuildStatus.BUILT - psi_checksolve_test( - ED, - [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], - test_results[mod], - 10000, - ) - end - end -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1b-2b)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_b_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], 5621.0, 10.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1c-2c)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_c_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], 21.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1d-2d)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_d_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], -5429.0, 10.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1e-2e)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_e_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], 21.0, 10.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1f-2f)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_f_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], -17179.0) -end - -### Feedforward Test ### - -@testset "Test SemiContinuousFeedforward to HydroDispatch with HydroCommitmentRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - ff_sc = SemiContinuousFeedforward(; - component_type = HydroDispatch, - source = OnVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_sc) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 96, 0, 72, 48, 0, true) -end - -@testset "Test UpperBoundFeedforward to HydroDispatch with HydroCommitmentRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - ff_ub = UpperBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 96, 0, 72, 24, 0, true) -end - -@testset "Test LowerBoundFeedforward to HydroDispatch with HydroCommitmentRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - ff_ub = LowerBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 96, 0, 48, 48, 0, true) -end - -@testset "Test UpperBoundFeedforward to HydroDispatch with HydroDispatchRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - - ff_ub = UpperBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 72, 0, 72, 24, 0, false) -end - -@testset "Test LowerBoundFeedforward to HydroDispatch with HydroDispatchRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - - ff_ub = LowerBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 72, 0, 48, 48, 0, false) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir with HydroDispatchReservoirBudget model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirBudget) - ff_il = EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 72, 0, 27, 24, 0, false) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir with HydroDispatchReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - ff_il = EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 193, 0, 26, 24, 48, false) -end - -@testset "Test LowerBoundFeedforward to HydroEnergyReservoir with HydroDispatchReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - ff_il = LowerBoundFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 193, 0, 24, 48, 48, false) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir with HydroCommitmentReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - ff_il = EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ) - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 217, 0, 26, 24, 48, true) -end - -@testset "Test SemiContinuousFeedforward to HydroEnergyReservoir with HydroCommitmentReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - ff_sc = SemiContinuousFeedforward(; - component_type = HydroEnergyReservoir, - source = OnVariable, - affected_values = [ActivePowerVariable], - ) - PSI.attach_feedforward!(device_model, ff_sc) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 217, 0, 48, 48, 48, true) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir models" begin - device_model = DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage) - - ff_il = EnergyLimitFeedforward(; - component_type = HydroPumpedStorage, - source = ActivePowerOutVariable, - affected_values = [ActivePowerOutVariable], - number_of_periods = 12, - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 110, 0, 25, 24, 24, true) -end - -@testset "Test EnergyTargetFeedforward to HydroEnergyReservoir models" begin - device_model = DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage) - - ff_up = EnergyTargetFeedforward(; - component_type = HydroPumpedStorage, - source = EnergyVariableUp, - affected_values = [EnergyVariableUp], - target_period = 12, - penalty_cost = 1e4, - ) - - PSI.attach_feedforward!(device_model, ff_up) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 122, 0, 24, 25, 24, true) -end diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index 4fd3a477a1..f0ba76db4a 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -132,29 +132,6 @@ end moi_tests(model, 360, 0, 72, 48, 72, false) end -@testset "Test Reserves from Hydro" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, PowerLoad, StaticPowerLoad) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchRunOfRiver) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve5"), - ) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveDown}, RangeReserve, "Reserve6"), - ) - set_service_model!( - template, - ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), - ) - - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; add_reserves = true) - model = DecisionModel(template, c_sys5_hyd) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 240, 0, 48, 96, 72, false) -end - @testset "Test Reserves from with slack variables" begin template = get_thermal_dispatch_template_network( NetworkModel(CopperPlatePowerModel; use_slacks = true), From 57a96544c6fb94c8cf6e80630ab10a89719048ec Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 25 Apr 2023 13:59:51 -0600 Subject: [PATCH 002/370] move more code --- src/PowerSimulations.jl | 5 ++- src/core/formulations.jl | 2 +- test/test_simulation_build.jl | 84 ----------------------------------- 3 files changed, 4 insertions(+), 87 deletions(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 9c41ad342c..853b0462ec 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -67,6 +67,9 @@ export ThermalCompactDispatch export DeviceLimitedRegulation export ReserveLimitedRegulation +###### Hydro ####### +export HydroDispatchRunOfRiver + # feedforward models export UpperBoundFeedforward export LowerBoundFeedforward @@ -523,7 +526,6 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") -include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") # Services Models @@ -545,7 +547,6 @@ include("initial_conditions/initialization.jl") # Device constructors include("devices_models/device_constructors/constructor_validations.jl") include("devices_models/device_constructors/thermalgeneration_constructor.jl") -include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 948289a0e0..4916aef959 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -78,7 +78,7 @@ abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ -struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end +struct HydroDispatchRunOfRiver <: AbstractHydroFormulation end ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end diff --git a/test/test_simulation_build.jl b/test/test_simulation_build.jl index 5acd725af5..b2fbe6589d 100644 --- a/test/test_simulation_build.jl +++ b/test/test_simulation_build.jl @@ -132,90 +132,6 @@ end @test_throws IS.ConflictingInputsError PSI._check_folder(sim) end -@testset "Multi-Stage Hydro Simulation Build" begin - sys_md = PSB.build_system(PSISystems, "5_bus_hydro_wk_sys") - - sys_uc = PSB.build_system(PSISystems, "5_bus_hydro_uc_sys") - transform_single_time_series!(sys_uc, 48, Hour(24)) - - sys_ed = PSB.build_system(PSISystems, "5_bus_hydro_ed_sys") - - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, ThermalStandard, ThermalBasicUnitCommitment) - set_device_model!(template, PowerLoad, StaticPowerLoad) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirBudget) - - template_uc = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template_uc, ThermalStandard, ThermalBasicUnitCommitment) - set_device_model!(template_uc, PowerLoad, StaticPowerLoad) - set_device_model!(template_uc, HydroEnergyReservoir, HydroDispatchRunOfRiver) - - template_ed = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template_ed, ThermalStandard, ThermalBasicUnitCommitment) - set_device_model!(template_ed, PowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchRunOfRiver) - - models = SimulationModels([ - DecisionModel( - template, - sys_md; - name = "MD", - initialize_model = false, - system_to_file = false, - optimizer = HiGHS_optimizer, - ), - DecisionModel( - template_uc, - sys_uc; - name = "UC", - initialize_model = false, - system_to_file = false, - optimizer = HiGHS_optimizer, - ), - DecisionModel( - template_ed, - sys_ed; - name = "ED", - initialize_model = false, - system_to_file = false, - optimizer = HiGHS_optimizer, - ), - ]) - - feedforwards = Dict( - "UC" => [ - EnergyLimitFeedforward(; - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - component_type = HydroEnergyReservoir, - number_of_periods = 24, - ), - ], - "ED" => [ - EnergyLimitFeedforward(; - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - component_type = HydroEnergyReservoir, - number_of_periods = 12, - ), - ], - ) - - test_sequence = SimulationSequence(; - models = models, - ini_cond_chronology = InterProblemChronology(), - feedforwards = feedforwards, - ) - - sim = Simulation(; - name = "test_md", - steps = 2, - models = models, - sequence = test_sequence, - simulation_folder = mktempdir(; cleanup = true), - ) - @test build!(sim; serialize = false) == PSI.BuildStatus.BUILT -end @testset "Test SemiContinuous Feedforward with Active and Reactive Power variables" begin template_uc = get_template_basic_uc_simulation() From 44bb6d3ef071b43a317949e312b7739abc69a9a5 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 9 May 2023 11:57:38 -0600 Subject: [PATCH 003/370] remove code --- docs/make.jl | 1 - docs/src/formulation_library/General.md | 8 +- docs/src/formulation_library/HydroGen.md | 494 ------ src/PowerSimulations.jl | 8 - src/core/formulations.jl | 33 - .../hydrogeneration_constructor.jl | 1482 ----------------- .../devices/hydro_generation.jl | 822 --------- ...st_device_hydro_generation_constructors.jl | 642 ------- test/test_services_constructor.jl | 23 - 9 files changed, 4 insertions(+), 3509 deletions(-) delete mode 100644 docs/src/formulation_library/HydroGen.md delete mode 100644 src/devices_models/device_constructors/hydrogeneration_constructor.jl delete mode 100644 src/devices_models/devices/hydro_generation.jl delete mode 100644 test/test_device_hydro_generation_constructors.jl diff --git a/docs/make.jl b/docs/make.jl index 0fc90a93a8..f2ec3aaedb 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -30,7 +30,6 @@ pages = OrderedDict( "Formulation Library" => Any[ "General" => "formulation_library/General.md", "Thermal Generation" => "formulation_library/ThermalGen.md", - "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", diff --git a/docs/src/formulation_library/General.md b/docs/src/formulation_library/General.md index 26d11eefa1..8b69c0803a 100644 --- a/docs/src/formulation_library/General.md +++ b/docs/src/formulation_library/General.md @@ -29,7 +29,7 @@ using PowerSystems using DataFrames using Latexify combo_tables = [] -for t in [RenewableGen, ThermalGen, HydroGen, Storage, ElectricLoad] +for t in [RenewableGen, ThermalGen, ElectricLoad] combos = PowerSimulations.get_default_time_series_names(t, FixedOutput) combo_table = DataFrame( "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), @@ -84,9 +84,9 @@ PowerSimulations can represent variable costs using a variety of different metho ### Piecewise Linear `VariableCost` -`variable_cost <: Vector{Tuple{Float64, Float64}}`: creates a piecewise linear cost term in the objective function +`variable_cost <: Vector{Tuple{Float64, Float64}}`: creates a piecewise linear cost term in the objective function -TODO: add formulation +TODO: add formulation ___ @@ -96,7 +96,7 @@ Adds an objective function cost term according to: ```math \begin{aligned} -& \text{min} \sum_{t} \quad [E^{surplus}_t * C^{penalty} - E^{shortage}_t * C^{value}] +& \text{min} \sum_{t} \quad [E^{surplus}_t * C^{penalty} - E^{shortage}_t * C^{value}] \end{aligned} ``` diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md deleted file mode 100644 index fa9358547d..0000000000 --- a/docs/src/formulation_library/HydroGen.md +++ /dev/null @@ -1,494 +0,0 @@ -# `PowerSystems.HydroGen` Formulations - -Valid `DeviceModel`s for subtypes of `HydroGen` include the following: - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.generate_device_formulation_combinations() -filter!(x -> x["device_type"] <: HydroGen, combos) -combo_table = DataFrame( - "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], - "Device Type" => ["[$(c["device_type"])](https://nrel-siip.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], - "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], - ) -mdtable(combo_table, latex = false) -``` - ---- - -## `HydroDispatchRunOfRiver` - -```@docs -HydroDispatchRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroDispatchRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} -\end{aligned} -``` - ---- - -## `HydroDispatchPumpedStorage` - -```@docs -HydroDispatchPumpedStorage -``` - -**Variables:** - -- [`ActivePowerInVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `-1 * PowerSystems.get_active_power(device)` -- [`ActivePowerOutVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`EnergyVariableUp`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device).up` -- [`EnergyVariableDown`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device).down` -- [`WaterSpillageVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`EnergyOutput`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`ReservationVariable`](@ref): - - only included if `DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage; attributes = Dict(reservation => true))` - - Bounds: {0, 1} - - Default initial value: 1 - -**Static Parameters:** - -- ``Pg^\text{out, max}`` = `map(x -> x.max - x.min, PowerSystems.get_active_power_limits(device))` -- ``Pg^\text{in, max}`` = `map(x -> x.max - x.min, PowerSystems.get_active_power_limits_pump(device))` -- ``Eg^\text{up, max}`` = `PowerSystems.get_storage_capacity(device).up` -- ``Eg^\text{down, max}`` = `PowerSystems.get_storage_capacity(device).down` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroPumpedStorage, HydroDispatchPumpedStorage) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg^{out}``. - -**Expressions:** - -Adds ``Pg`` term(s) to the active power balance expression(s) created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& E^{up}_{t+1} = E^{up}_t + (InflowTimeSeriesParameter_t - S_t - Pg^{out}_t + Pg^{in}_t) \cdot \Delta T \\ -& E^{down}_{t+1} = E^{down}_t + (S_t - OutflowTimeSeriesParameter_t + Pg^{out}_t - Pg^{in}_t) \cdot \Delta T \\ -& Pg^{in}_t - r * Pg^\text{in, max} \le Pg^\text{in, max} \\ -& Pg^{out}_t + r * Pg^\text{out, max} \le Pg^\text{out, max} \\ -& E^{up}_t \le E^{up, max} -& E^{down}_t \le E^{down, max} -\end{aligned} -``` - ---- - -## `HydroDispatchReservoirBudget` - -```@docs -HydroDispatchReservoirBudget -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - TODO - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroDispatchReservoirBudget) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg^\text{min} \le Pg_t \le Pg^\text{max} \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} \\ -& \sum_{t = 1}^N(Pg_t) \cdot \Delta T \le \sum_{t = 1}^N(EnergyBudgetTimeSeriesParameter_t) \cdot \Delta T -\end{aligned} -``` - ---- - -## `HydroDispatchReservoirStorage` - -```@docs -HydroDispatchReservoirStorage -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`EnergyVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device)` -- [`WaterSpillageVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`EnergyShortageVariable`](@ref): - - Bounds: [ , 0.0] - - Default initial value: 0.0 -- [`EnergySurplusVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` -- ``Eg^\text{max}`` = `PowerSystems.get_storage_capacity(device)` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroDispatchReservoirStorage) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. -TODO: add slack terms - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& E_{t+1} = E_t + (InflowTimeSeriesParameter_t - S_t - Pg_t) \cdot \Delta T \\ -& E_t - E^{surplus}_t + E^{shortage}_t = EnergyTargetTimeSeriesParameter_t \\ -& Pg^\text{min} \le Pg_t \le Pg^\text{max} \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} -\end{aligned} -``` - ---- - -## `HydroCommitmentReservoirBudget` - -```@docs -HydroCommitmentReservoirBudget -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - TODO - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroCommitmentReservoirBudget) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& \sum_{t = 1}^N P_t \cdot \Delta T \le E^\text{budget} \\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` - ---- - -## `HydroCommitmentReservoirStorage` - -```@docs -HydroCommitmentReservoirStorage -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`EnergyVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device)` -- [`WaterSpillageVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`EnergyShortageVariable`](@ref): - - Bounds: [ , 0.0] - - Default initial value: 0.0 -- [`EnergySurplusVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` -- ``Eg^\text{max}`` = `PowerSystems.get_storage_capacity(device)` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroCommitmentReservoirStorage) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``, -and objective function terms for [StorageManagementCost](@ref). - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& E_{t+1} = E_t + (InflowTimeSeriesParameter_t - S_t - Pg_t) \cdot \Delta T \\ -& E_t - E^{surplus}_t + E^{shortage}_t = EnergyTargetTimeSeriesParameter_t \\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` - ---- - -## `HydroCommitmentRunOfRiver` - -```@docs -HydroCommitmentRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroCommitmentRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg_t \le Pg^\text{max}\\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 51f5c64e42..c233c49bf3 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -51,14 +51,6 @@ export PowerLoadDispatch ######## Renewable Formulations ######## export RenewableFullDispatch export RenewableConstantPowerFactor -######## Hydro Formulations ######## -export HydroDispatchRunOfRiver -export HydroDispatchReservoirBudget -export HydroDispatchReservoirStorage -export HydroCommitmentRunOfRiver -export HydroCommitmentReservoirBudget -export HydroCommitmentReservoirStorage -export HydroDispatchPumpedStorage ######## Thermal Formulations ######## export ThermalStandardUnitCommitment diff --git a/src/core/formulations.jl b/src/core/formulations.jl index dedffc553a..948289a0e0 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -74,45 +74,12 @@ struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end ############################ Hydro Generation Formulations ################################# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end -abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end -abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end -abstract type AbstractHydroReservoirFormulation <: AbstractHydroDispatchFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end -""" -Formulation type to add injection variables constrained by total energy production budget defined with a time series for `HydroGen` -""" -struct HydroDispatchReservoirBudget <: AbstractHydroReservoirFormulation end - -""" -Formulation type to constrain hydropower production with a representation of the energy storage capacity and water inflow time series of a reservoir for `HydroGen` -""" -struct HydroDispatchReservoirStorage <: AbstractHydroReservoirFormulation end - -""" -Formulation type to constrain energy production from pumped storage with a representation of the energy storage capacity of upper and lower reservoirs and water inflow time series of upper reservoir and outflow time series of lower reservoir for `HydroPumpedStorage` -""" -struct HydroDispatchPumpedStorage <: AbstractHydroReservoirFormulation end - -""" -Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` -""" -struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end - -""" -Formulation type to add commitment and injection variables constrained by total energy production budget defined with a time series for `HydroGen` -""" -struct HydroCommitmentReservoirBudget <: AbstractHydroUnitCommitment end - -""" -Formulation type to constrain hydropower production with unit commitment variables and a representation of the energy storage capacity and water inflow time series of a reservoir for `HydroGen` -""" -struct HydroCommitmentReservoirStorage <: AbstractHydroUnitCommitment end - ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end struct ReserveLimitedRegulation <: AbstractRegulationFormulation end diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl deleted file mode 100644 index a2483f8e70..0000000000 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ /dev/null @@ -1,1482 +0,0 @@ -""" -Construct model for HydroGen with FixedOutput Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -function construct_device!( - ::OptimizationContainer, - ::PSY.System, - ::ModelConstructStage, - ::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - # FixedOutput doesn't add any constraints to the model. This function covers - # AbstractPowerModel and AbtractActivePowerModel - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -""" -Construct model for HydroGen with RunOfRiver Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with RunOfRiver Dispatch Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirBudget Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirBudget()) - add_variables!( - container, - ReactivePowerVariable, - devices, - HydroDispatchReservoirBudget(), - ) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirBudget()) - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirBudget Dispatch Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirBudget()) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirBudget()) - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with ReservoirStorage Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirStorage()) - add_variables!( - container, - ReactivePowerVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!(container, EnergyVariable, devices, HydroDispatchReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirStorage()) - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroDispatchReservoirStorage(), - InitialEnergyLevel(), - ) - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirStorage Dispatch Formulation -with only Active Power -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirStorage()) - add_variables!(container, EnergyVariable, devices, HydroDispatchReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirStorage()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroDispatchReservoirStorage(), - InitialEnergyLevel(), - ) - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirBudget Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentReservoirBudget, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentReservoirBudget, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with ReservoirBudget Commitment Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentReservoirBudget, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentReservoirBudget, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirStorage Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!( - container, - ActivePowerVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - ReactivePowerVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!(container, OnVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!(container, EnergyVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!(container, EnergyOutput, devices, HydroCommitmentReservoirStorage()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroCommitmentReservoirStorage(), - InitialEnergyLevel(), - ) - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with ReservoirStorage Dispatch Formulation -with only Active Power -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!( - container, - ActivePowerVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!(container, OnVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!(container, EnergyVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_variables!(container, EnergyOutput, devices, HydroCommitmentReservoirStorage()) - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroCommitmentReservoirStorage(), - InitialEnergyLevel(), - ) - - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroPumpedStorage with PumpedStorage Dispatch Formulation -with only Active Power -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchPumpedStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroPumpedStorage, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerInVariable, devices, HydroDispatchPumpedStorage()) - add_variables!(container, ActivePowerOutVariable, devices, HydroDispatchPumpedStorage()) - add_variables!(container, EnergyVariableUp, devices, HydroDispatchPumpedStorage()) - add_variables!(container, EnergyVariableDown, devices, HydroDispatchPumpedStorage()) - add_variables!(container, WaterSpillageVariable, devices, HydroDispatchPumpedStorage()) - add_variables!(container, EnergyOutput, devices, HydroDispatchPumpedStorage()) - if get_attribute(model, "reservation") - add_variables!( - container, - ReservationVariable, - devices, - HydroDispatchPumpedStorage(), - ) - end - - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - add_parameters!(container, OutflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerInVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ReserveRangeExpressionLB, devices, model) - add_expressions!(container, ReserveRangeExpressionUB, devices, model) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchPumpedStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroPumpedStorage, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - OutputActivePowerVariableLimitsConstraint, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - InputActivePowerVariableLimitsConstraint, - ActivePowerInVariable, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroDispatchPumpedStorage(), - InitialEnergyLevelUp(), - ) - add_initial_condition!( - container, - devices, - HydroDispatchPumpedStorage(), - InitialEnergyLevelDown(), - ) - - # Energy Balanace limits - add_constraints!(container, EnergyCapacityUpConstraint, devices, model, network_model) - add_constraints!(container, EnergyCapacityDownConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl deleted file mode 100644 index 65792bb3bf..0000000000 --- a/src/devices_models/devices/hydro_generation.jl +++ /dev/null @@ -1,822 +0,0 @@ -#! format: off -requires_initialization(::AbstractHydroFormulation) = false -requires_initialization(::AbstractHydroUnitCommitment) = true - -get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroPumpedStorage}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ReserveRangeExpressionUB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroPumpedStorage}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ReserveRangeExpressionLB - -########################### ActivePowerVariable, HydroGen ################################# -get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 -get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max - -############## ActivePowerVariable, HydroDispatchRunOfRiver #################### -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 - -############## ReactivePowerVariable, HydroGen #################### -get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min -get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max - -############## EnergyVariable, HydroGen #################### -get_variable_binary(::EnergyVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(pv::EnergyVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d) -get_variable_lower_bound(::EnergyVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) - -########################### EnergyVariableUp, HydroGen ################################# -get_variable_binary(::EnergyVariableUp, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(pv::EnergyVariableUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).up -get_variable_lower_bound(::EnergyVariableUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyVariableUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d).up - -########################### EnergyVariableDown, HydroGen ################################# -get_variable_binary(::EnergyVariableDown, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::EnergyVariableDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).down -get_variable_lower_bound(::EnergyVariableDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyVariableDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d).down - -########################### ActivePowerInVariable, HydroGen ################################# -get_variable_binary(::ActivePowerInVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::ActivePowerInVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::ActivePowerInVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = nothing -get_variable_multiplier(::ActivePowerInVariable, d::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = -1.0 - -########################### ActivePowerOutVariable, HydroGen ################################# -get_variable_binary(::ActivePowerOutVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::ActivePowerOutVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::ActivePowerOutVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = nothing -get_variable_multiplier(::ActivePowerOutVariable, d::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 - -############## OnVariable, HydroGen #################### -get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true -get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 - -############## WaterSpillageVariable, HydroGen #################### -get_variable_binary(::WaterSpillageVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::WaterSpillageVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 - -############## ReservationVariable, HydroGen #################### -get_variable_binary(::ReservationVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true -get_variable_binary(::ReservationVariable, ::Type{<:PSY.HydroPumpedStorage}, ::AbstractHydroFormulation) = true - -############## EnergyShortageVariable, HydroGen #################### -get_variable_binary(::EnergyShortageVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::EnergyShortageVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyShortageVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) -get_variable_upper_bound(::EnergyShortageVariable, d::PSY.HydroPumpedStorage, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d).up -############## EnergySurplusVariable, HydroGen #################### -get_variable_binary(::EnergySurplusVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_upper_bound(::EnergySurplusVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_lower_bound(::EnergySurplusVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = - PSY.get_storage_capacity(d) -get_variable_lower_bound(::EnergySurplusVariable, d::PSY.HydroPumpedStorage, ::AbstractHydroFormulation) = - PSY.get_storage_capacity(d).up -########################### Parameter related set functions ################################ -get_multiplier_value(::EnergyBudgetTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::EnergyBudgetTimeSeriesParameter, d::PSY.HydroEnergyReservoir, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) -get_multiplier_value(::EnergyTargetTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) -get_multiplier_value(::InflowTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_inflow(d) * PSY.get_conversion_factor(d) -get_multiplier_value(::OutflowTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_outflow(d) * PSY.get_conversion_factor(d) -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) - -get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min - -#################### Initial Conditions for models ############### -initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) -initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() -initial_condition_default(::InitialEnergyLevel, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d) -initial_condition_variable(::InitialEnergyLevel, d::PSY.HydroGen, ::AbstractHydroFormulation) = EnergyVariable() -initial_condition_default(::InitialEnergyLevelUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).up -initial_condition_variable(::InitialEnergyLevelUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = EnergyVariableUp() -initial_condition_default(::InitialEnergyLevelDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).down -initial_condition_variable(::InitialEnergyLevelDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = EnergyVariableDown() -initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 -initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) -initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() - -########################Objective Function################################################## -proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 -proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_surplus_cost(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_shortage_cost(cost) - -objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::EnergySurplusVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_NEGATIVE -objective_function_multiplier(::EnergyShortageVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE - -sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE -sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE - -variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 -variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) -variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) - -#! format: on - -function get_initial_conditions_device_model( - ::OperationModel, - model::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroEnergyReservoir} - return model -end - -function get_initial_conditions_device_model( - ::OperationModel, - ::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroDispatch} - return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) -end - -function get_initial_conditions_device_model( - ::OperationModel, - ::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroPumpedStorage} - return DeviceModel(PSY.HydroPumpedStorage, HydroDispatchPumpedStorage) -end - -function get_default_time_series_names( - ::Type{<:PSY.HydroGen}, - ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - ActivePowerTimeSeriesParameter => "max_active_power", - ReactivePowerTimeSeriesParameter => "max_active_power", - ) -end - -function get_default_time_series_names( - ::Type{PSY.HydroEnergyReservoir}, - ::Type{<:Union{HydroCommitmentReservoirBudget, HydroDispatchReservoirBudget}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - EnergyBudgetTimeSeriesParameter => "hydro_budget", - ) -end - -function get_default_time_series_names( - ::Type{PSY.HydroEnergyReservoir}, - ::Type{<:Union{HydroDispatchReservoirStorage, HydroCommitmentReservoirStorage}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - EnergyTargetTimeSeriesParameter => "storage_target", - InflowTimeSeriesParameter => "inflow", - ) -end - -function get_default_time_series_names( - ::Type{PSY.HydroPumpedStorage}, - ::Type{<:HydroDispatchPumpedStorage}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - InflowTimeSeriesParameter => "inflow", - OutflowTimeSeriesParameter => "outflow", - ) -end - -function get_default_attributes( - ::Type{T}, - ::Type{D}, -) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} - return Dict{String, Any}("reservation" => false) -end - -function get_default_attributes( - ::Type{PSY.HydroPumpedStorage}, - ::Type{HydroDispatchPumpedStorage}, -) - return Dict{String, Any}("reservation" => true) -end - -""" -Time series constraints -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:RangeConstraintLBExpressions}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -""" -Add semicontinuous range constraints for Hydro Unit Commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -""" -Min and max reactive Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ReactivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_reactive_power_limits(x) -end - -""" -Min and max active Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_active_power_limits(x) -end - -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchRunOfRiver}, -) - return (min = 0.0, max = PSY.get_max_active_power(x)) -end - -""" -Add power variable limits constraints for hydro unit commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -""" -Add power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroGen, - W <: AbstractHydroDispatchFormulation, - X <: PM.AbstractPowerModel, -} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -""" -Add input power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{InputActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroReservoirFormulation, - X <: PM.AbstractPowerModel, -} - if get_attribute(model, "reservation") - add_reserve_range_constraints!(container, T, U, devices, model, X) - else - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - end - return -end - -""" -Add output power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroReservoirFormulation, - X <: PM.AbstractPowerModel, -} - if get_attribute(model, "reservation") - add_reserve_range_constraints!(container, T, U, devices, model, X) - else - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - end - return -end - -""" -Min and max output active power variable limits for hydro dispatch pumped storage -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:OutputActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchPumpedStorage}, -) - return PSY.get_active_power_limits(x) -end - -""" -Min and max input active power variable limits for hydro dispatch pumped storage -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:InputActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchPumpedStorage}, -) - return PSY.get_active_power_limits_pump(x) -end - -######################## Energy balance constraints ############################ - -""" -This function defines the constraints for the water level (or state of charge) -for the Hydro Reservoir. -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyBalanceConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroEnergyReservoir, - W <: AbstractHydroFormulation, - X <: PM.AbstractPowerModel, -} - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - names = [PSY.get_name(x) for x in devices] - initial_conditions = get_initial_condition(container, InitialEnergyLevel(), V) - energy_var = get_variable(container, EnergyVariable(), V) - power_var = get_variable(container, ActivePowerVariable(), V) - spillage_var = get_variable(container, WaterSpillageVariable(), V) - - constraint = add_constraints_container!( - container, - EnergyBalanceConstraint(), - V, - names, - time_steps, - ) - param_container = get_parameter(container, InflowTimeSeriesParameter(), V) - multiplier = get_parameter_multiplier_array(container, InflowTimeSeriesParameter(), V) - - for ic in initial_conditions - device = get_component(ic) - name = PSY.get_name(device) - param = get_parameter_column_values(param_container, name) - constraint[name, 1] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, 1] == - get_value(ic) - power_var[name, 1] * fraction_of_hour - - spillage_var[name, 1] * fraction_of_hour + param[1] * multiplier[name, 1] - ) - - for t in time_steps[2:end] - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, t] == - energy_var[name, t - 1] + param[t] * multiplier[name, t] - - power_var[name, t] * fraction_of_hour - - spillage_var[name, t] * fraction_of_hour - ) - end - end - return -end - -""" -This function defines the constraints for the water level (or state of charge) -for the HydroPumpedStorage. -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyCapacityUpConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroFormulation, - X <: PM.AbstractPowerModel, -} - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - names = [PSY.get_name(x) for x in devices] - initial_conditions = get_initial_condition(container, InitialEnergyLevelUp(), V) - - energy_var = get_variable(container, EnergyVariableUp(), V) - powerin_var = get_variable(container, ActivePowerInVariable(), V) - powerout_var = get_variable(container, ActivePowerOutVariable(), V) - spillage_var = get_variable(container, WaterSpillageVariable(), V) - - constraint = add_constraints_container!( - container, - EnergyCapacityUpConstraint(), - V, - names, - time_steps, - ) - param_container = get_parameter(container, InflowTimeSeriesParameter(), V) - multiplier = get_multiplier_array(param_container) - - for ic in initial_conditions - device = get_component(ic) - efficiency = PSY.get_pump_efficiency(device) - name = PSY.get_name(device) - constraint[name, 1] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, 1] == - get_value(ic) + - ( - powerin_var[name, 1] - - (spillage_var[name, 1] + powerout_var[name, 1]) / efficiency - ) * fraction_of_hour + - get_parameter_column_refs(param_container, name)[1] * multiplier[name, 1] - ) - - for t in time_steps[2:end] - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, t] == - energy_var[name, t - 1] + - get_parameter_column_refs(param_container, name)[t] * multiplier[name, t] + - ( - powerin_var[name, 1] - - (powerout_var[name, t] + spillage_var[name, t]) / efficiency - ) * fraction_of_hour - ) - end - end - return -end - -""" -Add energy capacity down constraints for hydro pumped storage -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyCapacityDownConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroFormulation, - X <: PM.AbstractPowerModel, -} - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - names = [PSY.get_name(x) for x in devices] - initial_conditions = get_initial_condition(container, InitialEnergyLevelDown(), V) - - energy_var = get_variable(container, EnergyVariableDown(), V) - powerin_var = get_variable(container, ActivePowerInVariable(), V) - powerout_var = get_variable(container, ActivePowerOutVariable(), V) - spillage_var = get_variable(container, WaterSpillageVariable(), V) - - constraint = add_constraints_container!( - container, - EnergyCapacityDownConstraint(), - V, - names, - time_steps, - ) - - param_container = get_parameter(container, OutflowTimeSeriesParameter(), V) - multiplier = get_multiplier_array(param_container) - - for ic in initial_conditions - device = get_component(ic) - efficiency = PSY.get_pump_efficiency(device) - name = PSY.get_name(device) - param = get_parameter_column_refs(param_container, name) - constraint[name, 1] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, 1] == - get_value(ic) - - ( - spillage_var[name, 1] + powerout_var[name, 1] - - powerin_var[name, 1] / efficiency - ) * fraction_of_hour - param[1] * multiplier[name, 1] - ) - - for t in time_steps[2:end] - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, t] == - energy_var[name, t - 1] - param[t] * multiplier[name, t] + - ( - powerout_var[name, t] - powerin_var[name, t] / efficiency + - spillage_var[name, t] - ) * fraction_of_hour - ) - end - end - return -end - -""" -Add energy target constraints for hydro gen -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyTargetConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroFormulation, X <: PM.AbstractPowerModel} - time_steps = get_time_steps(container) - set_name = [PSY.get_name(d) for d in devices] - constraint = add_constraints_container!( - container, - EnergyTargetConstraint(), - V, - set_name, - time_steps, - ) - - e_var = get_variable(container, EnergyVariable(), V) - shortage_var = get_variable(container, EnergyShortageVariable(), V) - surplus_var = get_variable(container, EnergySurplusVariable(), V) - param_container = get_parameter(container, EnergyTargetTimeSeriesParameter(), V) - multiplier = - get_parameter_multiplier_array(container, EnergyTargetTimeSeriesParameter(), V) - - for d in devices - name = PSY.get_name(d) - cost_data = PSY.get_operation_cost(d) - if isa(cost_data, PSY.StorageManagementCost) - shortage_cost = PSY.get_energy_shortage_cost(cost_data) - else - @debug "Data for device $name doesn't contain shortage costs" - shortage_cost = 0.0 - end - - if shortage_cost == 0.0 - @warn( - "Device $name has energy shortage cost set to 0.0, as a result the model will turnoff the EnergyShortageVariable to avoid infeasible/unbounded problem." - ) - JuMP.delete_upper_bound.(shortage_var[name, :]) - JuMP.set_upper_bound.(shortage_var[name, :], 0.0) - end - param = get_parameter_column_values(param_container, name) - for t in time_steps - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - e_var[name, t] + shortage_var[name, t] + surplus_var[name, t] == - multiplier[name, t] * param[t] - ) - end - end - return -end - -##################################### Water/Energy Budget Constraint ############################ -""" -This function define the budget constraint for the -active power budget formulation. - -`` sum(P[t]) <= Budget `` -""" - -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyBudgetConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroFormulation, X <: PM.AbstractPowerModel} - time_steps = get_time_steps(container) - set_name = [PSY.get_name(d) for d in devices] - constraint = - add_constraints_container!(container, EnergyBudgetConstraint(), V, set_name) - - variable_out = get_variable(container, ActivePowerVariable(), V) - param_container = get_parameter(container, EnergyBudgetTimeSeriesParameter(), V) - multiplier = get_multiplier_array(param_container) - - for d in devices - name = PSY.get_name(d) - param = get_parameter_column_values(param_container, name) - constraint[name] = JuMP.@constraint( - container.JuMPmodel, - sum([variable_out[name, t] for t in time_steps]) <= - sum([multiplier[name, t] * param[t] for t in time_steps]) - ) - end - return -end - -##################################### Auxillary Variables ############################ -function _calculate_aux_variable_value!( - container::OptimizationContainer, - ::AuxVarKey{EnergyOutput, T}, - system::PSY.System, - p_variable_results::JuMPVariableArray, -) where {T <: PSY.HydroGen} - devices = axes(p_variable_results, 1) - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - aux_variable_container = get_aux_variable(container, EnergyOutput(), T) - for name in devices, t in time_steps - aux_variable_container[name, t] = - jump_value(p_variable_results[name, t]) * fraction_of_hour - end - - return -end - -function calculate_aux_variable_value!( - container::OptimizationContainer, - aux_key::AuxVarKey{EnergyOutput, T}, - system::PSY.System, -) where {T <: PSY.HydroGen} - p_variable_results = get_variable(container, ActivePowerVariable(), T) - _calculate_aux_variable_value!( - container, - aux_key, - system, - p_variable_results, - ) - return -end - -function calculate_aux_variable_value!( - container::OptimizationContainer, - aux_key::AuxVarKey{EnergyOutput, T}, - system::PSY.System, -) where {T <: PSY.HydroPumpedStorage} - p_variable_results = get_variable(container, ActivePowerOutVariable(), T) - _calculate_aux_variable_value!( - container, - aux_key, - system, - p_variable_results, - ) - return -end - -##################################### Hydro generation cost ############################ -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, OnVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{PSY.HydroPumpedStorage}, - ::DeviceModel{PSY.HydroPumpedStorage, T}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: HydroDispatchPumpedStorage} - add_variable_cost!(container, ActivePowerOutVariable(), devices, T()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where { - T <: PSY.HydroPumpedStorage, - U <: Union{HydroDispatchReservoirStorage, HydroDispatchReservoirBudget}, -} - add_variable_cost!(container, ActivePowerOutVariable(), devices, U()) - add_proportional_cost!(container, EnergySurplusVariable(), devices, U()) - add_proportional_cost!(container, EnergyShortageVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroEnergyReservoir, U <: HydroDispatchReservoirStorage} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, EnergySurplusVariable(), devices, U()) - add_proportional_cost!(container, EnergyShortageVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroEnergyReservoir, U <: HydroCommitmentReservoirStorage} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, EnergySurplusVariable(), devices, U()) - add_proportional_cost!(container, EnergyShortageVariable(), devices, U()) - return -end diff --git a/test/test_device_hydro_generation_constructors.jl b/test/test_device_hydro_generation_constructors.jl deleted file mode 100644 index ef37a71eab..0000000000 --- a/test/test_device_hydro_generation_constructors.jl +++ /dev/null @@ -1,642 +0,0 @@ -################################### -###### FIXED OUTPUT TESTS ######### -################################### - -@testset "Hydro DCPLossLess FixedOutput" begin - device_model = DeviceModel(HydroDispatch, FixedOutput) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with FixedOutput formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, FixedOutput) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -### RUN OF RIVER DISPATCH TESTS ### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -#### RUN OF RIVER COMMIT TESTS #### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -#### RESERVOIR BUDGET DISPATCH TESTS #### -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 25, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 49, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -#### PUMPED STORAGE DISPATCH TESTS #### -######################################### - -@testset "Hydro DCPLossLess HydroPumpedStorage with HydroDispatchPumpedStorage Formulations" begin - device_model = DeviceModel( - HydroPumpedStorage, - HydroDispatchPumpedStorage; - attributes = Dict{String, Any}("reservation" => false), - ) - c_sys5_phes_ed = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_phes_ed) - mock_construct_device!(model, device_model) - moi_tests(model, 60, 0, 24, 24, 24, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroPumpedStorage with HydroDispatchPumpedStorage with Reservation Formulations" begin - device_model = DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage) - c_sys5_phes_ed = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_phes_ed) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 24, 24, 24, true) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -### RESERVOIR BUDGET COMMITMENT TESTS ### -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 25, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 49, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -### RESERVOIR STORAGE DISPATCH TESTS #### -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 120, 0, 24, 24, 48, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPLossLess HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 144, 0, 48, 48, 48, false) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -### RESERVOIR STORAGE COMMITMENT TESTS ## -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 144, 0, 24, 24, 48, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPLossLess HydroEnergyReservoir with HydroCommitmentReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 168, 0, 48, 48, 48, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Solving ED Hydro System using Dispatch Run of River" begin - sys = PSB.build_system(PSITestSystems, "c_sys5_hy") - networks = [ACPPowerModel, DCPPowerModel] - - test_results = Dict{Any, Float64}(ACPPowerModel => 177526.0, DCPPowerModel => 175521.0) - - for net in networks - @testset "HydroRoR ED model $(net)" begin - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroDispatch, HydroDispatchRunOfRiver) - ED = DecisionModel( - EconomicDispatchProblem, - template, - sys; - optimizer = ipopt_optimizer, - ) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == - PSI.BuildStatus.BUILT - psi_checksolve_test( - ED, - [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], - test_results[net], - 1000, - ) - end - end -end - -@testset "Solving ED Hydro System using Commitment Run of River" begin - sys = PSB.build_system(PSITestSystems, "c_sys5_hy") - net = DCPPowerModel - - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroDispatch, HydroCommitmentRunOfRiver) - - @testset "HydroRoR ED model $(net)" begin - ED = DecisionModel(UnitCommitmentProblem, template, sys; optimizer = GLPK_optimizer) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - psi_checksolve_test(ED, [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], 175521.0, 1000) - end -end - -@testset "Solving ED Hydro System using Dispatch with Reservoir" begin - systems = [ - PSB.build_system(PSITestSystems, "c_sys5_hyd"), - PSB.build_system(PSITestSystems, "c_sys5_hyd_ems"), - ] - networks = [ACPPowerModel, DCPPowerModel] - models = [HydroDispatchReservoirBudget, HydroDispatchReservoirStorage] - test_results = Dict{Any, Float64}( - (ACPPowerModel, HydroDispatchReservoirBudget) => 33423.0, - (DCPPowerModel, HydroDispatchReservoirBudget) => 33042.0, - (ACPPowerModel, HydroDispatchReservoirStorage) => 232497.0, - (DCPPowerModel, HydroDispatchReservoirStorage) => 230153.0, - ) - - for net in networks, (mod, sys) in zip(models, systems) - @testset "$(mod) ED model on $(net)" begin - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroEnergyReservoir, mod) - - ED = DecisionModel( - EconomicDispatchProblem, - template, - sys; - optimizer = ipopt_optimizer, - ) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == - PSI.BuildStatus.BUILT - psi_checksolve_test( - ED, - [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], - test_results[(net, mod)], - 10000, - ) - end - end -end - -@testset "Solving ED Hydro System using Commitment with Reservoir" begin - systems = [ - PSB.build_system(PSITestSystems, "c_sys5_hyd"), - PSB.build_system(PSITestSystems, "c_sys5_hyd_ems"), - ] - net = DCPPowerModel - models = [HydroCommitmentReservoirBudget, HydroCommitmentReservoirStorage] - test_results = Dict{Any, Float64}( - HydroCommitmentReservoirBudget => 33042.0, - HydroCommitmentReservoirStorage => 230153.0, - ) - - for (mod, sys) in zip(models, systems) - @testset "$(mod) ED model on $(net) and use_parameters = true" begin - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroEnergyReservoir, mod) - - ED = DecisionModel( - UnitCommitmentProblem, - template, - sys; - optimizer = GLPK_optimizer, - ) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == - PSI.BuildStatus.BUILT - psi_checksolve_test( - ED, - [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], - test_results[mod], - 10000, - ) - end - end -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1b-2b)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_b_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], 5621.0, 10.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1c-2c)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_c_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], 21.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1d-2d)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_d_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], -5429.0, 10.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1e-2e)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_e_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], 21.0, 10.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1f-2f)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_f_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], -17179.0) -end - -### Feedforward Test ### - -@testset "Test SemiContinuousFeedforward to HydroDispatch with HydroCommitmentRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - ff_sc = SemiContinuousFeedforward(; - component_type = HydroDispatch, - source = OnVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_sc) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 96, 0, 72, 48, 0, true) -end - -@testset "Test UpperBoundFeedforward to HydroDispatch with HydroCommitmentRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - ff_ub = UpperBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 96, 0, 72, 24, 0, true) -end - -@testset "Test LowerBoundFeedforward to HydroDispatch with HydroCommitmentRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - ff_ub = LowerBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 96, 0, 48, 48, 0, true) -end - -@testset "Test UpperBoundFeedforward to HydroDispatch with HydroDispatchRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - - ff_ub = UpperBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 72, 0, 72, 24, 0, false) -end - -@testset "Test LowerBoundFeedforward to HydroDispatch with HydroDispatchRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - - ff_ub = LowerBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 72, 0, 48, 48, 0, false) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir with HydroDispatchReservoirBudget model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirBudget) - ff_il = EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 72, 0, 27, 24, 0, false) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir with HydroDispatchReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - ff_il = EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 193, 0, 26, 24, 48, false) -end - -@testset "Test LowerBoundFeedforward to HydroEnergyReservoir with HydroDispatchReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - ff_il = LowerBoundFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 193, 0, 24, 48, 48, false) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir with HydroCommitmentReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - ff_il = EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ) - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 217, 0, 26, 24, 48, true) -end - -@testset "Test SemiContinuousFeedforward to HydroEnergyReservoir with HydroCommitmentReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - ff_sc = SemiContinuousFeedforward(; - component_type = HydroEnergyReservoir, - source = OnVariable, - affected_values = [ActivePowerVariable], - ) - PSI.attach_feedforward!(device_model, ff_sc) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 217, 0, 48, 48, 48, true) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir models" begin - device_model = DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage) - - ff_il = EnergyLimitFeedforward(; - component_type = HydroPumpedStorage, - source = ActivePowerOutVariable, - affected_values = [ActivePowerOutVariable], - number_of_periods = 12, - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 110, 0, 25, 24, 24, true) -end - -@testset "Test EnergyTargetFeedforward to HydroEnergyReservoir models" begin - device_model = DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage) - - ff_up = EnergyTargetFeedforward(; - component_type = HydroPumpedStorage, - source = EnergyVariableUp, - affected_values = [EnergyVariableUp], - target_period = 12, - penalty_cost = 1e4, - ) - - PSI.attach_feedforward!(device_model, ff_up) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 122, 0, 24, 25, 24, true) -end diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index 9c4100a19c..c264dd41ac 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -132,29 +132,6 @@ end moi_tests(model, 360, 0, 72, 120, 72, false) end -@testset "Test Reserves from Hydro" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, PowerLoad, StaticPowerLoad) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchRunOfRiver) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve5"), - ) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveDown}, RangeReserve, "Reserve6"), - ) - set_service_model!( - template, - ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), - ) - - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; add_reserves = true) - model = DecisionModel(template, c_sys5_hyd) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 240, 0, 48, 96, 72, false) -end - @testset "Test Reserves from with slack variables" begin template = get_thermal_dispatch_template_network( NetworkModel(CopperPlatePowerModel; use_slacks = true), From fb3d55d61f70cae8a6eb634fb67c9b59fbe08e67 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 25 Apr 2023 13:59:51 -0600 Subject: [PATCH 004/370] move more code --- src/PowerSimulations.jl | 5 ++- src/core/formulations.jl | 2 +- test/test_simulation_build.jl | 84 ----------------------------------- 3 files changed, 4 insertions(+), 87 deletions(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index c233c49bf3..1992758d83 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -67,6 +67,9 @@ export ThermalCompactDispatch export DeviceLimitedRegulation export ReserveLimitedRegulation +###### Hydro ####### +export HydroDispatchRunOfRiver + # feedforward models export UpperBoundFeedforward export LowerBoundFeedforward @@ -522,7 +525,6 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") -include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") # Services Models @@ -544,7 +546,6 @@ include("initial_conditions/initialization.jl") # Device constructors include("devices_models/device_constructors/constructor_validations.jl") include("devices_models/device_constructors/thermalgeneration_constructor.jl") -include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 948289a0e0..4916aef959 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -78,7 +78,7 @@ abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ -struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end +struct HydroDispatchRunOfRiver <: AbstractHydroFormulation end ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end diff --git a/test/test_simulation_build.jl b/test/test_simulation_build.jl index 5acd725af5..b2fbe6589d 100644 --- a/test/test_simulation_build.jl +++ b/test/test_simulation_build.jl @@ -132,90 +132,6 @@ end @test_throws IS.ConflictingInputsError PSI._check_folder(sim) end -@testset "Multi-Stage Hydro Simulation Build" begin - sys_md = PSB.build_system(PSISystems, "5_bus_hydro_wk_sys") - - sys_uc = PSB.build_system(PSISystems, "5_bus_hydro_uc_sys") - transform_single_time_series!(sys_uc, 48, Hour(24)) - - sys_ed = PSB.build_system(PSISystems, "5_bus_hydro_ed_sys") - - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, ThermalStandard, ThermalBasicUnitCommitment) - set_device_model!(template, PowerLoad, StaticPowerLoad) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirBudget) - - template_uc = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template_uc, ThermalStandard, ThermalBasicUnitCommitment) - set_device_model!(template_uc, PowerLoad, StaticPowerLoad) - set_device_model!(template_uc, HydroEnergyReservoir, HydroDispatchRunOfRiver) - - template_ed = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template_ed, ThermalStandard, ThermalBasicUnitCommitment) - set_device_model!(template_ed, PowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchRunOfRiver) - - models = SimulationModels([ - DecisionModel( - template, - sys_md; - name = "MD", - initialize_model = false, - system_to_file = false, - optimizer = HiGHS_optimizer, - ), - DecisionModel( - template_uc, - sys_uc; - name = "UC", - initialize_model = false, - system_to_file = false, - optimizer = HiGHS_optimizer, - ), - DecisionModel( - template_ed, - sys_ed; - name = "ED", - initialize_model = false, - system_to_file = false, - optimizer = HiGHS_optimizer, - ), - ]) - - feedforwards = Dict( - "UC" => [ - EnergyLimitFeedforward(; - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - component_type = HydroEnergyReservoir, - number_of_periods = 24, - ), - ], - "ED" => [ - EnergyLimitFeedforward(; - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - component_type = HydroEnergyReservoir, - number_of_periods = 12, - ), - ], - ) - - test_sequence = SimulationSequence(; - models = models, - ini_cond_chronology = InterProblemChronology(), - feedforwards = feedforwards, - ) - - sim = Simulation(; - name = "test_md", - steps = 2, - models = models, - sequence = test_sequence, - simulation_folder = mktempdir(; cleanup = true), - ) - @test build!(sim; serialize = false) == PSI.BuildStatus.BUILT -end @testset "Test SemiContinuous Feedforward with Active and Reactive Power variables" begin template_uc = get_template_basic_uc_simulation() From 87f4e11e2b9516bdd5af04d418c1e073ed4b09b5 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:35 -0700 Subject: [PATCH 005/370] bring back hydro constructors --- src/PowerSimulations.jl | 3 + src/core/formulations.jl | 9 +- .../hydrogeneration_constructor.jl | 468 ++++++++++++++++++ .../devices/hydro_generation.jl | 297 +++++++++++ 4 files changed, 776 insertions(+), 1 deletion(-) create mode 100644 src/devices_models/device_constructors/hydrogeneration_constructor.jl create mode 100644 src/devices_models/devices/hydro_generation.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 1992758d83..6c8fcd65ee 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -69,6 +69,7 @@ export ReserveLimitedRegulation ###### Hydro ####### export HydroDispatchRunOfRiver +export HydroCommitmentRunOfRiver # feedforward models export UpperBoundFeedforward @@ -525,6 +526,7 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") +include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") # Services Models @@ -546,6 +548,7 @@ include("initial_conditions/initialization.jl") # Device constructors include("devices_models/device_constructors/constructor_validations.jl") include("devices_models/device_constructors/thermalgeneration_constructor.jl") +include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 4916aef959..7522280c51 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -74,11 +74,18 @@ struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end ############################ Hydro Generation Formulations ################################# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end +abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end +abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ -struct HydroDispatchRunOfRiver <: AbstractHydroFormulation end +struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end + +""" +Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` +""" +struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl new file mode 100644 index 0000000000..75673eba77 --- /dev/null +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -0,0 +1,468 @@ +""" +Construct model for HydroGen with FixedOutput Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) + + # Expression + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + return +end + +function construct_device!( + ::OptimizationContainer, + ::PSY.System, + ::ModelConstructStage, + ::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} + # FixedOutput doesn't add any constraints to the model. This function covers + # AbstractPowerModel and AbstractActivePowerModel + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + # Expression + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + return +end + +""" +Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractPowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, ReactivePowerVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractPowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_constraints!( + container, + ReactivePowerVariableLimitsConstraint, + ReactivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + add_constraint_dual!(container, sys, model) + + return +end + +""" +Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation +with only Active Power. +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end + +""" +Construct model for HydroGen with RunOfRiver Commitment Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, ReactivePowerVariable, devices, D()) + add_variables!(container, OnVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_constraints!( + container, + ReactivePowerVariableLimitsConstraint, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end + +""" +Construct model for HydroGen with RunOfRiver Commitment Formulation +with only Active Power. +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: HydroCommitmentRunOfRiver, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, OnVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: HydroCommitmentRunOfRiver, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl new file mode 100644 index 0000000000..69e861b2c7 --- /dev/null +++ b/src/devices_models/devices/hydro_generation.jl @@ -0,0 +1,297 @@ +#! format: off +requires_initialization(::AbstractHydroFormulation) = false +requires_initialization(::AbstractHydroUnitCommitment) = true + +get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 +get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB +get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB + +########################### ActivePowerVariable, HydroGen ################################# +get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false +get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 +get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max + +############## ActivePowerVariable, HydroDispatchRunOfRiver #################### +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 + +############## ReactivePowerVariable, HydroGen #################### +get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false +get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power(d) +get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).min +get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).max + +############## OnVariable, HydroGen #################### +get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true +get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 + +########################### Parameter related set functions ################################ +get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) +get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) + +get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 +get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 +get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max +get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min + +#################### Initial Conditions for models ############### +initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) +initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() +initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) +initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() +initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 +initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() +initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) +initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() + +########################Objective Function################################################## +proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 +proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) +proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_surplus_cost(cost) +proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_shortage_cost(cost) + +objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::EnergySurplusVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_NEGATIVE +objective_function_multiplier(::EnergyShortageVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE + +sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE +sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE + +variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 +variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) +variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) + +#! format: on + +function get_initial_conditions_device_model( + ::OperationModel, + model::DeviceModel{T, <:AbstractHydroFormulation}, +) where {T <: PSY.HydroEnergyReservoir} + return model +end + +function get_initial_conditions_device_model( + ::OperationModel, + ::DeviceModel{T, <:AbstractHydroFormulation}, +) where {T <: PSY.HydroDispatch} + return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) +end + +function get_default_time_series_names( + ::Type{<:PSY.HydroGen}, + ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, +) + return Dict{Type{<:TimeSeriesParameter}, String}( + ActivePowerTimeSeriesParameter => "max_active_power", + ReactivePowerTimeSeriesParameter => "max_active_power", + ) +end + +function get_default_attributes( + ::Type{T}, + ::Type{D}, +) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} + return Dict{String, Any}("reservation" => false) +end + +""" +Time series constraints +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + add_parameterized_upper_bound_range_constraints( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + U, + ActivePowerTimeSeriesParameter, + devices, + model, + X, + ) + return +end + +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:RangeConstraintLBExpressions}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + return +end + +""" +Add semicontinuous range constraints for Hydro Unit Commitment formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + return +end + +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + add_parameterized_upper_bound_range_constraints( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + U, + ActivePowerTimeSeriesParameter, + devices, + model, + X, + ) + return +end + +""" +Min and max reactive Power Variable limits +""" +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ReactivePowerVariableLimitsConstraint}, + ::Type{<:AbstractHydroFormulation}, +) + return PSY.get_reactive_power_limits(x) +end + +""" +Min and max active Power Variable limits +""" +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ActivePowerVariableLimitsConstraint}, + ::Type{<:AbstractHydroFormulation}, +) + return PSY.get_active_power_limits(x) +end + +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ActivePowerVariableLimitsConstraint}, + ::Type{HydroDispatchRunOfRiver}, +) + return (min = 0.0, max = PSY.get_max_active_power(x)) +end + +""" +Add power variable limits constraints for hydro unit commitment formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{<:PowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + return +end + +""" +Add power variable limits constraints for hydro dispatch formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{<:PowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where { + V <: PSY.HydroGen, + W <: AbstractHydroDispatchFormulation, + X <: PM.AbstractPowerModel, +} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + return +end + +##################################### Auxillary Variables ############################ +function _calculate_aux_variable_value!( + container::OptimizationContainer, + ::AuxVarKey{EnergyOutput, T}, + system::PSY.System, + p_variable_results::JuMPVariableArray, +) where {T <: PSY.HydroGen} + devices = axes(p_variable_results, 1) + time_steps = get_time_steps(container) + resolution = get_resolution(container) + fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR + aux_variable_container = get_aux_variable(container, EnergyOutput(), T) + for name in devices, t in time_steps + aux_variable_container[name, t] = + jump_value(p_variable_results[name, t]) * fraction_of_hour + end + + return +end + +function calculate_aux_variable_value!( + container::OptimizationContainer, + aux_key::AuxVarKey{EnergyOutput, T}, + system::PSY.System, +) where {T <: PSY.HydroGen} + p_variable_results = get_variable(container, ActivePowerVariable(), T) + _calculate_aux_variable_value!( + container, + aux_key, + system, + p_variable_results, + ) + return +end + +##################################### Hydro generation cost ############################ +function objective_function!( + container::OptimizationContainer, + devices::IS.FlattenIteratorWrapper{T}, + ::DeviceModel{T, U}, + ::Type{<:PM.AbstractPowerModel}, +) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} + add_variable_cost!(container, ActivePowerVariable(), devices, U()) + add_proportional_cost!(container, OnVariable(), devices, U()) + return +end + +function objective_function!( + container::OptimizationContainer, + devices::IS.FlattenIteratorWrapper{T}, + ::DeviceModel{T, U}, + ::Type{<:PM.AbstractPowerModel}, +) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} + add_variable_cost!(container, ActivePowerVariable(), devices, U()) + return +end From edf2b1e142252dbf1502593811ed6b184ef39f62 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:42 -0700 Subject: [PATCH 006/370] bring back hydro tests --- ...st_device_hydro_generation_constructors.jl | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 test/test_device_hydro_generation_constructors.jl diff --git a/test/test_device_hydro_generation_constructors.jl b/test/test_device_hydro_generation_constructors.jl new file mode 100644 index 0000000000..7545c57ace --- /dev/null +++ b/test/test_device_hydro_generation_constructors.jl @@ -0,0 +1,121 @@ +################################### +###### FIXED OUTPUT TESTS ######### +################################### + +@testset "Hydro DCPLossLess FixedOutput" begin + device_model = DeviceModel(HydroDispatch, FixedOutput) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 0, 0, 0, 0, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with FixedOutput formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, FixedOutput) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 0, 0, 0, 0, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +################################### +### RUN OF RIVER DISPATCH TESTS ### +################################### + +@testset "Hydro DCPLossLess HydroDispatch with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 24, 0, 48, 24, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroDispatch with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 72, 48, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 24, 0, 48, 24, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 72, 48, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +################################### +#### RUN OF RIVER COMMIT TESTS #### +################################### + +@testset "Hydro DCPLossLess HydroDispatch with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 48, 24, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroDispatch with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 72, 0, 72, 48, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 48, 24, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 72, 0, 72, 48, 0, true) + psi_checkobjfun_test(model, GAEVF) +end From 709a2230cd4f45d003ef3bf0f8d65f5bbb4efbfb Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:57 -0700 Subject: [PATCH 007/370] remove reservoir budget from tests --- test/test_model_decision.jl | 62 ------------------ test/test_model_emulation.jl | 104 ------------------------------ test/test_print.jl | 7 -- test/test_services_constructor.jl | 23 +++++++ test/test_simulation_build.jl | 1 - test/test_simulation_execute.jl | 14 ---- test/test_simulation_results.jl | 11 +--- 7 files changed, 25 insertions(+), 197 deletions(-) diff --git a/test/test_model_decision.jl b/test/test_model_decision.jl index c2d4299938..d0eb4610f1 100644 --- a/test/test_model_decision.jl +++ b/test/test_model_decision.jl @@ -488,68 +488,6 @@ end HydroEnergyReservoir, ) @test solve!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroDispatchReservoirBudget ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; force_build = true) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirBudget) - model = DecisionModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test !PSI.has_initial_condition_value( - initial_conditions_data, - ActivePowerVariable(), - HydroEnergyReservoir, - ) - @test solve!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentReservoirBudget ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; force_build = true) - set_device_model!(template, HydroEnergyReservoir, HydroCommitmentReservoirBudget) - model = DecisionModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test PSI.has_initial_condition_value( - initial_conditions_data, - OnVariable(), - HydroEnergyReservoir, - ) - @test solve!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroDispatchReservoirStorage ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems"; force_build = true) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - model = DecisionModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test !PSI.has_initial_condition_value( - initial_conditions_data, - ActivePowerVariable(), - HydroEnergyReservoir, - ) - check_energy_initial_conditions_values(model, HydroEnergyReservoir) - @test solve!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentReservoirStorage ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems"; force_build = true) - set_device_model!(template, HydroEnergyReservoir, HydroCommitmentReservoirStorage) - model = DecisionModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test PSI.has_initial_condition_value( - initial_conditions_data, - OnVariable(), - HydroEnergyReservoir, - ) - check_energy_initial_conditions_values(model, HydroEnergyReservoir) - @test solve!(model) == RunStatus.SUCCESSFUL end @testset "Test serialization of InitialConditionsData" begin diff --git a/test/test_model_emulation.jl b/test/test_model_emulation.jl index ba40caa9ba..06baefcf7f 100644 --- a/test/test_model_emulation.jl +++ b/test/test_model_emulation.jl @@ -142,110 +142,6 @@ end HydroEnergyReservoir, ) @test run!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentRunOfRiver ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system( - PSITestSystems, - "c_sys5_hyd"; - add_single_time_series = true, - force_build = true, - ) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirBudget) - model = EmulationModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; executions = 10, output_dir = mktempdir(; cleanup = true)) == - BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test !PSI.has_initial_condition_value( - initial_conditions_data, - ActivePowerVariable(), - HydroEnergyReservoir, - ) - @test run!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentRunOfRiver ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system( - PSITestSystems, - "c_sys5_hyd"; - add_single_time_series = true, - force_build = true, - ) - set_device_model!(template, HydroEnergyReservoir, HydroCommitmentReservoirBudget) - model = EmulationModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; executions = 10, output_dir = mktempdir(; cleanup = true)) == - BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test PSI.has_initial_condition_value( - initial_conditions_data, - OnVariable(), - HydroEnergyReservoir, - ) - @test run!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentRunOfRiver ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system( - PSITestSystems, - "c_sys5_hyd_ems"; - add_single_time_series = true, - force_build = true, - ) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - model = EmulationModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; executions = 10, output_dir = mktempdir(; cleanup = true)) == - BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test !PSI.has_initial_condition_value( - initial_conditions_data, - ActivePowerVariable(), - HydroEnergyReservoir, - ) - ic_data = PSI.get_initial_condition( - PSI.get_optimization_container(model), - InitialEnergyLevel(), - HydroEnergyReservoir, - ) - for ic in ic_data - name = PSY.get_name(ic.component) - e_var = PSI.jump_value(PSI.get_value(ic)) - @test PSY.get_initial_storage(ic.component) == e_var - end - @test run!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentRunOfRiver ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system( - PSITestSystems, - "c_sys5_hyd_ems"; - add_single_time_series = true, - force_build = true, - ) - set_device_model!(template, HydroEnergyReservoir, HydroCommitmentReservoirStorage) - model = EmulationModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; executions = 10, output_dir = mktempdir(; cleanup = true)) == - BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test PSI.has_initial_condition_value( - initial_conditions_data, - OnVariable(), - HydroEnergyReservoir, - ) - ic_data = PSI.get_initial_condition( - PSI.get_optimization_container(model), - InitialEnergyLevel(), - HydroEnergyReservoir, - ) - for ic in ic_data - name = PSY.get_name(ic.component) - e_var = PSI.jump_value(PSI.get_value(ic)) - @test PSY.get_initial_storage(ic.component) == e_var - end - @test run!(model) == RunStatus.SUCCESSFUL end @testset "Emulation Model Results" begin diff --git a/test/test_print.jl b/test/test_print.jl index 43c154d02a..ff1e6108ea 100644 --- a/test/test_print.jl +++ b/test/test_print.jl @@ -45,7 +45,6 @@ end template_uc = get_template_basic_uc_simulation() template_ed = get_template_nomin_ed_simulation() set_device_model!(template_ed, InterruptiblePowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchReservoirBudget) set_network_model!(template_uc, NetworkModel( CopperPlatePowerModel, # MILP "duals" not supported with free solvers @@ -88,12 +87,6 @@ end source = OnVariable, affected_values = [ActivePowerVariable], ), - EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ), ], ), ini_cond_chronology = InterProblemChronology(), diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index c264dd41ac..9c4100a19c 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -132,6 +132,29 @@ end moi_tests(model, 360, 0, 72, 120, 72, false) end +@testset "Test Reserves from Hydro" begin + template = ProblemTemplate(CopperPlatePowerModel) + set_device_model!(template, PowerLoad, StaticPowerLoad) + set_device_model!(template, HydroEnergyReservoir, HydroDispatchRunOfRiver) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve5"), + ) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveDown}, RangeReserve, "Reserve6"), + ) + set_service_model!( + template, + ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), + ) + + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; add_reserves = true) + model = DecisionModel(template, c_sys5_hyd) + @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT + moi_tests(model, 240, 0, 48, 96, 72, false) +end + @testset "Test Reserves from with slack variables" begin template = get_thermal_dispatch_template_network( NetworkModel(CopperPlatePowerModel; use_slacks = true), diff --git a/test/test_simulation_build.jl b/test/test_simulation_build.jl index b2fbe6589d..5bda0fa750 100644 --- a/test/test_simulation_build.jl +++ b/test/test_simulation_build.jl @@ -132,7 +132,6 @@ end @test_throws IS.ConflictingInputsError PSI._check_folder(sim) end - @testset "Test SemiContinuous Feedforward with Active and Reactive Power variables" begin template_uc = get_template_basic_uc_simulation() set_network_model!(template_uc, NetworkModel(DCPPowerModel; use_slacks = true)) diff --git a/test/test_simulation_execute.jl b/test/test_simulation_execute.jl index 783c4c5241..f50bab178f 100644 --- a/test/test_simulation_execute.jl +++ b/test/test_simulation_execute.jl @@ -38,7 +38,6 @@ function test_2_stage_decision_models_with_feedforwards(in_memory) template_uc = get_template_basic_uc_simulation() template_ed = get_template_nomin_ed_simulation() set_device_model!(template_ed, InterruptiblePowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchReservoirBudget) set_network_model!(template_uc, NetworkModel( CopperPlatePowerModel, # MILP "duals" not supported with free solvers @@ -80,12 +79,6 @@ function test_2_stage_decision_models_with_feedforwards(in_memory) source = OnVariable, affected_values = [ActivePowerVariable], ), - EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ), ], ), ini_cond_chronology = InterProblemChronology(), @@ -128,7 +121,6 @@ end ), ) set_device_model!(template_ed, InterruptiblePowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchReservoirBudget) c_sys5_hy_uc = PSB.build_system(PSITestSystems, "c_sys5_hy_uc") c_sys5_hy_ed = PSB.build_system(PSITestSystems, "c_sys5_hy_ed") models = SimulationModels(; @@ -157,12 +149,6 @@ end source = OnVariable, affected_values = [ActivePowerVariable], ), - EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ), ], ), ini_cond_chronology = InterProblemChronology(), diff --git a/test/test_simulation_results.jl b/test/test_simulation_results.jl index 98525c9302..4b8816d043 100644 --- a/test/test_simulation_results.jl +++ b/test/test_simulation_results.jl @@ -132,7 +132,6 @@ function test_simulation_results(file_path::String, export_path; in_memory = fal template_uc = get_template_basic_uc_simulation() template_ed = get_template_nomin_ed_simulation() set_device_model!(template_ed, InterruptiblePowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchReservoirBudget) set_network_model!( template_uc, NetworkModel(CopperPlatePowerModel; duals = [CopperPlateBalanceConstraint]), @@ -173,12 +172,6 @@ function test_simulation_results(file_path::String, export_path; in_memory = fal source = OnVariable, affected_values = [ActivePowerVariable], ), - EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ), ], ), ini_cond_chronology = InterProblemChronology(), @@ -230,7 +223,7 @@ function test_simulation_results(file_path::String, export_path; in_memory = fal verify_export_results(results, export_path) - @test length(readdir(export_realized_results(results_ed))) === 18 + @test length(readdir(export_realized_results(results_ed))) === 17 # Test that you can't read a failed simulation. PSI.set_simulation_status!(sim, RunStatus.FAILED) @@ -547,7 +540,7 @@ function test_emulation_problem_results(results::SimulationResults, in_memory) ) == 10 parameters_keys = collect(keys(read_realized_parameters(results_em))) - @test length(parameters_keys) == 7 + @test length(parameters_keys) == 5 parameters_inputs = ( [ "ActivePowerTimeSeriesParameter__PowerLoad", From e886af23e6b9593fdb5e01273d869533eaf6fa80 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 13:04:52 -0700 Subject: [PATCH 008/370] bring back hydro docs --- docs/make.jl | 1 + docs/src/formulation_library/General.md | 2 +- docs/src/formulation_library/HydroGen.md | 134 +++++++++++++++++++++++ 3 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 docs/src/formulation_library/HydroGen.md diff --git a/docs/make.jl b/docs/make.jl index f2ec3aaedb..0fc90a93a8 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -30,6 +30,7 @@ pages = OrderedDict( "Formulation Library" => Any[ "General" => "formulation_library/General.md", "Thermal Generation" => "formulation_library/ThermalGen.md", + "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", diff --git a/docs/src/formulation_library/General.md b/docs/src/formulation_library/General.md index 8b69c0803a..e5912b268c 100644 --- a/docs/src/formulation_library/General.md +++ b/docs/src/formulation_library/General.md @@ -29,7 +29,7 @@ using PowerSystems using DataFrames using Latexify combo_tables = [] -for t in [RenewableGen, ThermalGen, ElectricLoad] +for t in [RenewableGen, ThermalGen, HydroGen, ElectricLoad] combos = PowerSimulations.get_default_time_series_names(t, FixedOutput) combo_table = DataFrame( "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md new file mode 100644 index 0000000000..efe13982b3 --- /dev/null +++ b/docs/src/formulation_library/HydroGen.md @@ -0,0 +1,134 @@ +# `PowerSystems.HydroGen` Formulations + +Valid `DeviceModel`s for subtypes of `HydroGen` include the following: + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.generate_device_formulation_combinations() +filter!(x -> x["device_type"] <: HydroGen, combos) +combo_table = DataFrame( + "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], + "Device Type" => ["[$(c["device_type"])](https://nrel-siip.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], + "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], + ) +mdtable(combo_table, latex = false) +``` + +--- + +## `HydroDispatchRunOfRiver` + +```@docs +HydroDispatchRunOfRiver +``` + +**Variables:** + +- [`ActivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_active_power(device)` +- [`ReactivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_reactive_power(device)` + +**Static Parameters:** + +- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` +- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` +- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` + +**Time Series Parameters:** + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroDispatchRunOfRiver) +combo_table = DataFrame( + "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), + "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), + ) +mdtable(combo_table, latex = false) +``` + +**Objective:** + +Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg``. + +**Expressions:** + +Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) + +**Constraints:** + +```math +\begin{aligned} +& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ +& Qg^\text{min} \le Qg_t \le Qg^\text{max} +\end{aligned} +``` + +--- + +## `HydroCommitmentRunOfRiver` + +```@docs +HydroCommitmentRunOfRiver +``` + +**Variables:** + +- [`ActivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_active_power(device)` +- [`ReactivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_reactive_power(device)` +- [`OnVariable`](@ref): + - Bounds: {0, 1} + - Default initial value: `PowerSystems.get_status(device)` + +**Static Parameters:** + +- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` +- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` +- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` + +**Time Series Parameters:** + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroCommitmentRunOfRiver) +combo_table = DataFrame( + "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), + "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), + ) +mdtable(combo_table, latex = false) +``` + +**Objective:** + +Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. + +**Expressions:** + +Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) + +**Constraints:** + +```math +\begin{aligned} +& Pg_t \le Pg^\text{max}\\ +& Pg_t - u_t Pg^\text{max} \le 0 \\ +& Pg_t - u_t Pg^\text{min} \ge 0 \\ +& Qg_t - u_t Qg^\text{max} \le 0 \\ +& Qg_t - u_t Qg^\text{min} \ge 0 +\end{aligned} +``` \ No newline at end of file From f2ba6c9ab60905cdef4b505559bfc4a0f2ce77ed Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 9 May 2023 11:57:38 -0600 Subject: [PATCH 009/370] remove code --- docs/make.jl | 1 - docs/src/formulation_library/General.md | 8 +- docs/src/formulation_library/HydroGen.md | 494 ------ src/PowerSimulations.jl | 8 - src/core/formulations.jl | 33 - .../hydrogeneration_constructor.jl | 1482 ----------------- .../devices/hydro_generation.jl | 822 --------- ...st_device_hydro_generation_constructors.jl | 642 ------- test/test_services_constructor.jl | 23 - 9 files changed, 4 insertions(+), 3509 deletions(-) delete mode 100644 docs/src/formulation_library/HydroGen.md delete mode 100644 src/devices_models/device_constructors/hydrogeneration_constructor.jl delete mode 100644 src/devices_models/devices/hydro_generation.jl delete mode 100644 test/test_device_hydro_generation_constructors.jl diff --git a/docs/make.jl b/docs/make.jl index 0fc90a93a8..f2ec3aaedb 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -30,7 +30,6 @@ pages = OrderedDict( "Formulation Library" => Any[ "General" => "formulation_library/General.md", "Thermal Generation" => "formulation_library/ThermalGen.md", - "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", diff --git a/docs/src/formulation_library/General.md b/docs/src/formulation_library/General.md index 26d11eefa1..8b69c0803a 100644 --- a/docs/src/formulation_library/General.md +++ b/docs/src/formulation_library/General.md @@ -29,7 +29,7 @@ using PowerSystems using DataFrames using Latexify combo_tables = [] -for t in [RenewableGen, ThermalGen, HydroGen, Storage, ElectricLoad] +for t in [RenewableGen, ThermalGen, ElectricLoad] combos = PowerSimulations.get_default_time_series_names(t, FixedOutput) combo_table = DataFrame( "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), @@ -84,9 +84,9 @@ PowerSimulations can represent variable costs using a variety of different metho ### Piecewise Linear `VariableCost` -`variable_cost <: Vector{Tuple{Float64, Float64}}`: creates a piecewise linear cost term in the objective function +`variable_cost <: Vector{Tuple{Float64, Float64}}`: creates a piecewise linear cost term in the objective function -TODO: add formulation +TODO: add formulation ___ @@ -96,7 +96,7 @@ Adds an objective function cost term according to: ```math \begin{aligned} -& \text{min} \sum_{t} \quad [E^{surplus}_t * C^{penalty} - E^{shortage}_t * C^{value}] +& \text{min} \sum_{t} \quad [E^{surplus}_t * C^{penalty} - E^{shortage}_t * C^{value}] \end{aligned} ``` diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md deleted file mode 100644 index fa9358547d..0000000000 --- a/docs/src/formulation_library/HydroGen.md +++ /dev/null @@ -1,494 +0,0 @@ -# `PowerSystems.HydroGen` Formulations - -Valid `DeviceModel`s for subtypes of `HydroGen` include the following: - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.generate_device_formulation_combinations() -filter!(x -> x["device_type"] <: HydroGen, combos) -combo_table = DataFrame( - "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], - "Device Type" => ["[$(c["device_type"])](https://nrel-siip.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], - "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], - ) -mdtable(combo_table, latex = false) -``` - ---- - -## `HydroDispatchRunOfRiver` - -```@docs -HydroDispatchRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroDispatchRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} -\end{aligned} -``` - ---- - -## `HydroDispatchPumpedStorage` - -```@docs -HydroDispatchPumpedStorage -``` - -**Variables:** - -- [`ActivePowerInVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `-1 * PowerSystems.get_active_power(device)` -- [`ActivePowerOutVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`EnergyVariableUp`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device).up` -- [`EnergyVariableDown`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device).down` -- [`WaterSpillageVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`EnergyOutput`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`ReservationVariable`](@ref): - - only included if `DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage; attributes = Dict(reservation => true))` - - Bounds: {0, 1} - - Default initial value: 1 - -**Static Parameters:** - -- ``Pg^\text{out, max}`` = `map(x -> x.max - x.min, PowerSystems.get_active_power_limits(device))` -- ``Pg^\text{in, max}`` = `map(x -> x.max - x.min, PowerSystems.get_active_power_limits_pump(device))` -- ``Eg^\text{up, max}`` = `PowerSystems.get_storage_capacity(device).up` -- ``Eg^\text{down, max}`` = `PowerSystems.get_storage_capacity(device).down` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroPumpedStorage, HydroDispatchPumpedStorage) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg^{out}``. - -**Expressions:** - -Adds ``Pg`` term(s) to the active power balance expression(s) created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& E^{up}_{t+1} = E^{up}_t + (InflowTimeSeriesParameter_t - S_t - Pg^{out}_t + Pg^{in}_t) \cdot \Delta T \\ -& E^{down}_{t+1} = E^{down}_t + (S_t - OutflowTimeSeriesParameter_t + Pg^{out}_t - Pg^{in}_t) \cdot \Delta T \\ -& Pg^{in}_t - r * Pg^\text{in, max} \le Pg^\text{in, max} \\ -& Pg^{out}_t + r * Pg^\text{out, max} \le Pg^\text{out, max} \\ -& E^{up}_t \le E^{up, max} -& E^{down}_t \le E^{down, max} -\end{aligned} -``` - ---- - -## `HydroDispatchReservoirBudget` - -```@docs -HydroDispatchReservoirBudget -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - TODO - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroDispatchReservoirBudget) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg^\text{min} \le Pg_t \le Pg^\text{max} \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} \\ -& \sum_{t = 1}^N(Pg_t) \cdot \Delta T \le \sum_{t = 1}^N(EnergyBudgetTimeSeriesParameter_t) \cdot \Delta T -\end{aligned} -``` - ---- - -## `HydroDispatchReservoirStorage` - -```@docs -HydroDispatchReservoirStorage -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`EnergyVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device)` -- [`WaterSpillageVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`EnergyShortageVariable`](@ref): - - Bounds: [ , 0.0] - - Default initial value: 0.0 -- [`EnergySurplusVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` -- ``Eg^\text{max}`` = `PowerSystems.get_storage_capacity(device)` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroDispatchReservoirStorage) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. -TODO: add slack terms - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& E_{t+1} = E_t + (InflowTimeSeriesParameter_t - S_t - Pg_t) \cdot \Delta T \\ -& E_t - E^{surplus}_t + E^{shortage}_t = EnergyTargetTimeSeriesParameter_t \\ -& Pg^\text{min} \le Pg_t \le Pg^\text{max} \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} -\end{aligned} -``` - ---- - -## `HydroCommitmentReservoirBudget` - -```@docs -HydroCommitmentReservoirBudget -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - TODO - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroCommitmentReservoirBudget) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& \sum_{t = 1}^N P_t \cdot \Delta T \le E^\text{budget} \\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` - ---- - -## `HydroCommitmentReservoirStorage` - -```@docs -HydroCommitmentReservoirStorage -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`EnergyVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device)` -- [`WaterSpillageVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`EnergyShortageVariable`](@ref): - - Bounds: [ , 0.0] - - Default initial value: 0.0 -- [`EnergySurplusVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` -- ``Eg^\text{max}`` = `PowerSystems.get_storage_capacity(device)` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroCommitmentReservoirStorage) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``, -and objective function terms for [StorageManagementCost](@ref). - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& E_{t+1} = E_t + (InflowTimeSeriesParameter_t - S_t - Pg_t) \cdot \Delta T \\ -& E_t - E^{surplus}_t + E^{shortage}_t = EnergyTargetTimeSeriesParameter_t \\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` - ---- - -## `HydroCommitmentRunOfRiver` - -```@docs -HydroCommitmentRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroCommitmentRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg_t \le Pg^\text{max}\\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index b1e31398f6..7b0705a91e 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -51,14 +51,6 @@ export PowerLoadDispatch ######## Renewable Formulations ######## export RenewableFullDispatch export RenewableConstantPowerFactor -######## Hydro Formulations ######## -export HydroDispatchRunOfRiver -export HydroDispatchReservoirBudget -export HydroDispatchReservoirStorage -export HydroCommitmentRunOfRiver -export HydroCommitmentReservoirBudget -export HydroCommitmentReservoirStorage -export HydroDispatchPumpedStorage ######## Thermal Formulations ######## export ThermalStandardUnitCommitment diff --git a/src/core/formulations.jl b/src/core/formulations.jl index dedffc553a..948289a0e0 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -74,45 +74,12 @@ struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end ############################ Hydro Generation Formulations ################################# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end -abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end -abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end -abstract type AbstractHydroReservoirFormulation <: AbstractHydroDispatchFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end -""" -Formulation type to add injection variables constrained by total energy production budget defined with a time series for `HydroGen` -""" -struct HydroDispatchReservoirBudget <: AbstractHydroReservoirFormulation end - -""" -Formulation type to constrain hydropower production with a representation of the energy storage capacity and water inflow time series of a reservoir for `HydroGen` -""" -struct HydroDispatchReservoirStorage <: AbstractHydroReservoirFormulation end - -""" -Formulation type to constrain energy production from pumped storage with a representation of the energy storage capacity of upper and lower reservoirs and water inflow time series of upper reservoir and outflow time series of lower reservoir for `HydroPumpedStorage` -""" -struct HydroDispatchPumpedStorage <: AbstractHydroReservoirFormulation end - -""" -Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` -""" -struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end - -""" -Formulation type to add commitment and injection variables constrained by total energy production budget defined with a time series for `HydroGen` -""" -struct HydroCommitmentReservoirBudget <: AbstractHydroUnitCommitment end - -""" -Formulation type to constrain hydropower production with unit commitment variables and a representation of the energy storage capacity and water inflow time series of a reservoir for `HydroGen` -""" -struct HydroCommitmentReservoirStorage <: AbstractHydroUnitCommitment end - ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end struct ReserveLimitedRegulation <: AbstractRegulationFormulation end diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl deleted file mode 100644 index a2483f8e70..0000000000 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ /dev/null @@ -1,1482 +0,0 @@ -""" -Construct model for HydroGen with FixedOutput Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -function construct_device!( - ::OptimizationContainer, - ::PSY.System, - ::ModelConstructStage, - ::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - # FixedOutput doesn't add any constraints to the model. This function covers - # AbstractPowerModel and AbtractActivePowerModel - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -""" -Construct model for HydroGen with RunOfRiver Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with RunOfRiver Dispatch Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirBudget Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirBudget()) - add_variables!( - container, - ReactivePowerVariable, - devices, - HydroDispatchReservoirBudget(), - ) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirBudget()) - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirBudget Dispatch Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirBudget()) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirBudget()) - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with ReservoirStorage Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirStorage()) - add_variables!( - container, - ReactivePowerVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!(container, EnergyVariable, devices, HydroDispatchReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirStorage()) - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroDispatchReservoirStorage(), - InitialEnergyLevel(), - ) - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirStorage Dispatch Formulation -with only Active Power -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirStorage()) - add_variables!(container, EnergyVariable, devices, HydroDispatchReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirStorage()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroDispatchReservoirStorage(), - InitialEnergyLevel(), - ) - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirBudget Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentReservoirBudget, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentReservoirBudget, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with ReservoirBudget Commitment Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentReservoirBudget, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentReservoirBudget, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirStorage Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!( - container, - ActivePowerVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - ReactivePowerVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!(container, OnVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!(container, EnergyVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!(container, EnergyOutput, devices, HydroCommitmentReservoirStorage()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroCommitmentReservoirStorage(), - InitialEnergyLevel(), - ) - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with ReservoirStorage Dispatch Formulation -with only Active Power -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!( - container, - ActivePowerVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!(container, OnVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!(container, EnergyVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_variables!(container, EnergyOutput, devices, HydroCommitmentReservoirStorage()) - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroCommitmentReservoirStorage(), - InitialEnergyLevel(), - ) - - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroPumpedStorage with PumpedStorage Dispatch Formulation -with only Active Power -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchPumpedStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroPumpedStorage, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerInVariable, devices, HydroDispatchPumpedStorage()) - add_variables!(container, ActivePowerOutVariable, devices, HydroDispatchPumpedStorage()) - add_variables!(container, EnergyVariableUp, devices, HydroDispatchPumpedStorage()) - add_variables!(container, EnergyVariableDown, devices, HydroDispatchPumpedStorage()) - add_variables!(container, WaterSpillageVariable, devices, HydroDispatchPumpedStorage()) - add_variables!(container, EnergyOutput, devices, HydroDispatchPumpedStorage()) - if get_attribute(model, "reservation") - add_variables!( - container, - ReservationVariable, - devices, - HydroDispatchPumpedStorage(), - ) - end - - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - add_parameters!(container, OutflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerInVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ReserveRangeExpressionLB, devices, model) - add_expressions!(container, ReserveRangeExpressionUB, devices, model) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchPumpedStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroPumpedStorage, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - OutputActivePowerVariableLimitsConstraint, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - InputActivePowerVariableLimitsConstraint, - ActivePowerInVariable, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroDispatchPumpedStorage(), - InitialEnergyLevelUp(), - ) - add_initial_condition!( - container, - devices, - HydroDispatchPumpedStorage(), - InitialEnergyLevelDown(), - ) - - # Energy Balanace limits - add_constraints!(container, EnergyCapacityUpConstraint, devices, model, network_model) - add_constraints!(container, EnergyCapacityDownConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl deleted file mode 100644 index 65792bb3bf..0000000000 --- a/src/devices_models/devices/hydro_generation.jl +++ /dev/null @@ -1,822 +0,0 @@ -#! format: off -requires_initialization(::AbstractHydroFormulation) = false -requires_initialization(::AbstractHydroUnitCommitment) = true - -get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroPumpedStorage}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ReserveRangeExpressionUB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroPumpedStorage}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ReserveRangeExpressionLB - -########################### ActivePowerVariable, HydroGen ################################# -get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 -get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max - -############## ActivePowerVariable, HydroDispatchRunOfRiver #################### -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 - -############## ReactivePowerVariable, HydroGen #################### -get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min -get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max - -############## EnergyVariable, HydroGen #################### -get_variable_binary(::EnergyVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(pv::EnergyVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d) -get_variable_lower_bound(::EnergyVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) - -########################### EnergyVariableUp, HydroGen ################################# -get_variable_binary(::EnergyVariableUp, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(pv::EnergyVariableUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).up -get_variable_lower_bound(::EnergyVariableUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyVariableUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d).up - -########################### EnergyVariableDown, HydroGen ################################# -get_variable_binary(::EnergyVariableDown, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::EnergyVariableDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).down -get_variable_lower_bound(::EnergyVariableDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyVariableDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d).down - -########################### ActivePowerInVariable, HydroGen ################################# -get_variable_binary(::ActivePowerInVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::ActivePowerInVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::ActivePowerInVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = nothing -get_variable_multiplier(::ActivePowerInVariable, d::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = -1.0 - -########################### ActivePowerOutVariable, HydroGen ################################# -get_variable_binary(::ActivePowerOutVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::ActivePowerOutVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::ActivePowerOutVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = nothing -get_variable_multiplier(::ActivePowerOutVariable, d::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 - -############## OnVariable, HydroGen #################### -get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true -get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 - -############## WaterSpillageVariable, HydroGen #################### -get_variable_binary(::WaterSpillageVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::WaterSpillageVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 - -############## ReservationVariable, HydroGen #################### -get_variable_binary(::ReservationVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true -get_variable_binary(::ReservationVariable, ::Type{<:PSY.HydroPumpedStorage}, ::AbstractHydroFormulation) = true - -############## EnergyShortageVariable, HydroGen #################### -get_variable_binary(::EnergyShortageVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::EnergyShortageVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyShortageVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) -get_variable_upper_bound(::EnergyShortageVariable, d::PSY.HydroPumpedStorage, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d).up -############## EnergySurplusVariable, HydroGen #################### -get_variable_binary(::EnergySurplusVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_upper_bound(::EnergySurplusVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_lower_bound(::EnergySurplusVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = - PSY.get_storage_capacity(d) -get_variable_lower_bound(::EnergySurplusVariable, d::PSY.HydroPumpedStorage, ::AbstractHydroFormulation) = - PSY.get_storage_capacity(d).up -########################### Parameter related set functions ################################ -get_multiplier_value(::EnergyBudgetTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::EnergyBudgetTimeSeriesParameter, d::PSY.HydroEnergyReservoir, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) -get_multiplier_value(::EnergyTargetTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) -get_multiplier_value(::InflowTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_inflow(d) * PSY.get_conversion_factor(d) -get_multiplier_value(::OutflowTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_outflow(d) * PSY.get_conversion_factor(d) -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) - -get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min - -#################### Initial Conditions for models ############### -initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) -initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() -initial_condition_default(::InitialEnergyLevel, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d) -initial_condition_variable(::InitialEnergyLevel, d::PSY.HydroGen, ::AbstractHydroFormulation) = EnergyVariable() -initial_condition_default(::InitialEnergyLevelUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).up -initial_condition_variable(::InitialEnergyLevelUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = EnergyVariableUp() -initial_condition_default(::InitialEnergyLevelDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).down -initial_condition_variable(::InitialEnergyLevelDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = EnergyVariableDown() -initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 -initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) -initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() - -########################Objective Function################################################## -proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 -proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_surplus_cost(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_shortage_cost(cost) - -objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::EnergySurplusVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_NEGATIVE -objective_function_multiplier(::EnergyShortageVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE - -sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE -sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE - -variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 -variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) -variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) - -#! format: on - -function get_initial_conditions_device_model( - ::OperationModel, - model::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroEnergyReservoir} - return model -end - -function get_initial_conditions_device_model( - ::OperationModel, - ::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroDispatch} - return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) -end - -function get_initial_conditions_device_model( - ::OperationModel, - ::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroPumpedStorage} - return DeviceModel(PSY.HydroPumpedStorage, HydroDispatchPumpedStorage) -end - -function get_default_time_series_names( - ::Type{<:PSY.HydroGen}, - ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - ActivePowerTimeSeriesParameter => "max_active_power", - ReactivePowerTimeSeriesParameter => "max_active_power", - ) -end - -function get_default_time_series_names( - ::Type{PSY.HydroEnergyReservoir}, - ::Type{<:Union{HydroCommitmentReservoirBudget, HydroDispatchReservoirBudget}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - EnergyBudgetTimeSeriesParameter => "hydro_budget", - ) -end - -function get_default_time_series_names( - ::Type{PSY.HydroEnergyReservoir}, - ::Type{<:Union{HydroDispatchReservoirStorage, HydroCommitmentReservoirStorage}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - EnergyTargetTimeSeriesParameter => "storage_target", - InflowTimeSeriesParameter => "inflow", - ) -end - -function get_default_time_series_names( - ::Type{PSY.HydroPumpedStorage}, - ::Type{<:HydroDispatchPumpedStorage}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - InflowTimeSeriesParameter => "inflow", - OutflowTimeSeriesParameter => "outflow", - ) -end - -function get_default_attributes( - ::Type{T}, - ::Type{D}, -) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} - return Dict{String, Any}("reservation" => false) -end - -function get_default_attributes( - ::Type{PSY.HydroPumpedStorage}, - ::Type{HydroDispatchPumpedStorage}, -) - return Dict{String, Any}("reservation" => true) -end - -""" -Time series constraints -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:RangeConstraintLBExpressions}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -""" -Add semicontinuous range constraints for Hydro Unit Commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -""" -Min and max reactive Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ReactivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_reactive_power_limits(x) -end - -""" -Min and max active Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_active_power_limits(x) -end - -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchRunOfRiver}, -) - return (min = 0.0, max = PSY.get_max_active_power(x)) -end - -""" -Add power variable limits constraints for hydro unit commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -""" -Add power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroGen, - W <: AbstractHydroDispatchFormulation, - X <: PM.AbstractPowerModel, -} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -""" -Add input power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{InputActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroReservoirFormulation, - X <: PM.AbstractPowerModel, -} - if get_attribute(model, "reservation") - add_reserve_range_constraints!(container, T, U, devices, model, X) - else - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - end - return -end - -""" -Add output power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroReservoirFormulation, - X <: PM.AbstractPowerModel, -} - if get_attribute(model, "reservation") - add_reserve_range_constraints!(container, T, U, devices, model, X) - else - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - end - return -end - -""" -Min and max output active power variable limits for hydro dispatch pumped storage -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:OutputActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchPumpedStorage}, -) - return PSY.get_active_power_limits(x) -end - -""" -Min and max input active power variable limits for hydro dispatch pumped storage -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:InputActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchPumpedStorage}, -) - return PSY.get_active_power_limits_pump(x) -end - -######################## Energy balance constraints ############################ - -""" -This function defines the constraints for the water level (or state of charge) -for the Hydro Reservoir. -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyBalanceConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroEnergyReservoir, - W <: AbstractHydroFormulation, - X <: PM.AbstractPowerModel, -} - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - names = [PSY.get_name(x) for x in devices] - initial_conditions = get_initial_condition(container, InitialEnergyLevel(), V) - energy_var = get_variable(container, EnergyVariable(), V) - power_var = get_variable(container, ActivePowerVariable(), V) - spillage_var = get_variable(container, WaterSpillageVariable(), V) - - constraint = add_constraints_container!( - container, - EnergyBalanceConstraint(), - V, - names, - time_steps, - ) - param_container = get_parameter(container, InflowTimeSeriesParameter(), V) - multiplier = get_parameter_multiplier_array(container, InflowTimeSeriesParameter(), V) - - for ic in initial_conditions - device = get_component(ic) - name = PSY.get_name(device) - param = get_parameter_column_values(param_container, name) - constraint[name, 1] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, 1] == - get_value(ic) - power_var[name, 1] * fraction_of_hour - - spillage_var[name, 1] * fraction_of_hour + param[1] * multiplier[name, 1] - ) - - for t in time_steps[2:end] - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, t] == - energy_var[name, t - 1] + param[t] * multiplier[name, t] - - power_var[name, t] * fraction_of_hour - - spillage_var[name, t] * fraction_of_hour - ) - end - end - return -end - -""" -This function defines the constraints for the water level (or state of charge) -for the HydroPumpedStorage. -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyCapacityUpConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroFormulation, - X <: PM.AbstractPowerModel, -} - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - names = [PSY.get_name(x) for x in devices] - initial_conditions = get_initial_condition(container, InitialEnergyLevelUp(), V) - - energy_var = get_variable(container, EnergyVariableUp(), V) - powerin_var = get_variable(container, ActivePowerInVariable(), V) - powerout_var = get_variable(container, ActivePowerOutVariable(), V) - spillage_var = get_variable(container, WaterSpillageVariable(), V) - - constraint = add_constraints_container!( - container, - EnergyCapacityUpConstraint(), - V, - names, - time_steps, - ) - param_container = get_parameter(container, InflowTimeSeriesParameter(), V) - multiplier = get_multiplier_array(param_container) - - for ic in initial_conditions - device = get_component(ic) - efficiency = PSY.get_pump_efficiency(device) - name = PSY.get_name(device) - constraint[name, 1] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, 1] == - get_value(ic) + - ( - powerin_var[name, 1] - - (spillage_var[name, 1] + powerout_var[name, 1]) / efficiency - ) * fraction_of_hour + - get_parameter_column_refs(param_container, name)[1] * multiplier[name, 1] - ) - - for t in time_steps[2:end] - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, t] == - energy_var[name, t - 1] + - get_parameter_column_refs(param_container, name)[t] * multiplier[name, t] + - ( - powerin_var[name, 1] - - (powerout_var[name, t] + spillage_var[name, t]) / efficiency - ) * fraction_of_hour - ) - end - end - return -end - -""" -Add energy capacity down constraints for hydro pumped storage -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyCapacityDownConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroFormulation, - X <: PM.AbstractPowerModel, -} - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - names = [PSY.get_name(x) for x in devices] - initial_conditions = get_initial_condition(container, InitialEnergyLevelDown(), V) - - energy_var = get_variable(container, EnergyVariableDown(), V) - powerin_var = get_variable(container, ActivePowerInVariable(), V) - powerout_var = get_variable(container, ActivePowerOutVariable(), V) - spillage_var = get_variable(container, WaterSpillageVariable(), V) - - constraint = add_constraints_container!( - container, - EnergyCapacityDownConstraint(), - V, - names, - time_steps, - ) - - param_container = get_parameter(container, OutflowTimeSeriesParameter(), V) - multiplier = get_multiplier_array(param_container) - - for ic in initial_conditions - device = get_component(ic) - efficiency = PSY.get_pump_efficiency(device) - name = PSY.get_name(device) - param = get_parameter_column_refs(param_container, name) - constraint[name, 1] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, 1] == - get_value(ic) - - ( - spillage_var[name, 1] + powerout_var[name, 1] - - powerin_var[name, 1] / efficiency - ) * fraction_of_hour - param[1] * multiplier[name, 1] - ) - - for t in time_steps[2:end] - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, t] == - energy_var[name, t - 1] - param[t] * multiplier[name, t] + - ( - powerout_var[name, t] - powerin_var[name, t] / efficiency + - spillage_var[name, t] - ) * fraction_of_hour - ) - end - end - return -end - -""" -Add energy target constraints for hydro gen -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyTargetConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroFormulation, X <: PM.AbstractPowerModel} - time_steps = get_time_steps(container) - set_name = [PSY.get_name(d) for d in devices] - constraint = add_constraints_container!( - container, - EnergyTargetConstraint(), - V, - set_name, - time_steps, - ) - - e_var = get_variable(container, EnergyVariable(), V) - shortage_var = get_variable(container, EnergyShortageVariable(), V) - surplus_var = get_variable(container, EnergySurplusVariable(), V) - param_container = get_parameter(container, EnergyTargetTimeSeriesParameter(), V) - multiplier = - get_parameter_multiplier_array(container, EnergyTargetTimeSeriesParameter(), V) - - for d in devices - name = PSY.get_name(d) - cost_data = PSY.get_operation_cost(d) - if isa(cost_data, PSY.StorageManagementCost) - shortage_cost = PSY.get_energy_shortage_cost(cost_data) - else - @debug "Data for device $name doesn't contain shortage costs" - shortage_cost = 0.0 - end - - if shortage_cost == 0.0 - @warn( - "Device $name has energy shortage cost set to 0.0, as a result the model will turnoff the EnergyShortageVariable to avoid infeasible/unbounded problem." - ) - JuMP.delete_upper_bound.(shortage_var[name, :]) - JuMP.set_upper_bound.(shortage_var[name, :], 0.0) - end - param = get_parameter_column_values(param_container, name) - for t in time_steps - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - e_var[name, t] + shortage_var[name, t] + surplus_var[name, t] == - multiplier[name, t] * param[t] - ) - end - end - return -end - -##################################### Water/Energy Budget Constraint ############################ -""" -This function define the budget constraint for the -active power budget formulation. - -`` sum(P[t]) <= Budget `` -""" - -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyBudgetConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroFormulation, X <: PM.AbstractPowerModel} - time_steps = get_time_steps(container) - set_name = [PSY.get_name(d) for d in devices] - constraint = - add_constraints_container!(container, EnergyBudgetConstraint(), V, set_name) - - variable_out = get_variable(container, ActivePowerVariable(), V) - param_container = get_parameter(container, EnergyBudgetTimeSeriesParameter(), V) - multiplier = get_multiplier_array(param_container) - - for d in devices - name = PSY.get_name(d) - param = get_parameter_column_values(param_container, name) - constraint[name] = JuMP.@constraint( - container.JuMPmodel, - sum([variable_out[name, t] for t in time_steps]) <= - sum([multiplier[name, t] * param[t] for t in time_steps]) - ) - end - return -end - -##################################### Auxillary Variables ############################ -function _calculate_aux_variable_value!( - container::OptimizationContainer, - ::AuxVarKey{EnergyOutput, T}, - system::PSY.System, - p_variable_results::JuMPVariableArray, -) where {T <: PSY.HydroGen} - devices = axes(p_variable_results, 1) - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - aux_variable_container = get_aux_variable(container, EnergyOutput(), T) - for name in devices, t in time_steps - aux_variable_container[name, t] = - jump_value(p_variable_results[name, t]) * fraction_of_hour - end - - return -end - -function calculate_aux_variable_value!( - container::OptimizationContainer, - aux_key::AuxVarKey{EnergyOutput, T}, - system::PSY.System, -) where {T <: PSY.HydroGen} - p_variable_results = get_variable(container, ActivePowerVariable(), T) - _calculate_aux_variable_value!( - container, - aux_key, - system, - p_variable_results, - ) - return -end - -function calculate_aux_variable_value!( - container::OptimizationContainer, - aux_key::AuxVarKey{EnergyOutput, T}, - system::PSY.System, -) where {T <: PSY.HydroPumpedStorage} - p_variable_results = get_variable(container, ActivePowerOutVariable(), T) - _calculate_aux_variable_value!( - container, - aux_key, - system, - p_variable_results, - ) - return -end - -##################################### Hydro generation cost ############################ -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, OnVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{PSY.HydroPumpedStorage}, - ::DeviceModel{PSY.HydroPumpedStorage, T}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: HydroDispatchPumpedStorage} - add_variable_cost!(container, ActivePowerOutVariable(), devices, T()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where { - T <: PSY.HydroPumpedStorage, - U <: Union{HydroDispatchReservoirStorage, HydroDispatchReservoirBudget}, -} - add_variable_cost!(container, ActivePowerOutVariable(), devices, U()) - add_proportional_cost!(container, EnergySurplusVariable(), devices, U()) - add_proportional_cost!(container, EnergyShortageVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroEnergyReservoir, U <: HydroDispatchReservoirStorage} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, EnergySurplusVariable(), devices, U()) - add_proportional_cost!(container, EnergyShortageVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroEnergyReservoir, U <: HydroCommitmentReservoirStorage} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, EnergySurplusVariable(), devices, U()) - add_proportional_cost!(container, EnergyShortageVariable(), devices, U()) - return -end diff --git a/test/test_device_hydro_generation_constructors.jl b/test/test_device_hydro_generation_constructors.jl deleted file mode 100644 index ef37a71eab..0000000000 --- a/test/test_device_hydro_generation_constructors.jl +++ /dev/null @@ -1,642 +0,0 @@ -################################### -###### FIXED OUTPUT TESTS ######### -################################### - -@testset "Hydro DCPLossLess FixedOutput" begin - device_model = DeviceModel(HydroDispatch, FixedOutput) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with FixedOutput formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, FixedOutput) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -### RUN OF RIVER DISPATCH TESTS ### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -#### RUN OF RIVER COMMIT TESTS #### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -#### RESERVOIR BUDGET DISPATCH TESTS #### -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 25, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 49, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -#### PUMPED STORAGE DISPATCH TESTS #### -######################################### - -@testset "Hydro DCPLossLess HydroPumpedStorage with HydroDispatchPumpedStorage Formulations" begin - device_model = DeviceModel( - HydroPumpedStorage, - HydroDispatchPumpedStorage; - attributes = Dict{String, Any}("reservation" => false), - ) - c_sys5_phes_ed = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_phes_ed) - mock_construct_device!(model, device_model) - moi_tests(model, 60, 0, 24, 24, 24, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroPumpedStorage with HydroDispatchPumpedStorage with Reservation Formulations" begin - device_model = DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage) - c_sys5_phes_ed = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_phes_ed) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 24, 24, 24, true) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -### RESERVOIR BUDGET COMMITMENT TESTS ### -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 25, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 49, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -### RESERVOIR STORAGE DISPATCH TESTS #### -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 120, 0, 24, 24, 48, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPLossLess HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 144, 0, 48, 48, 48, false) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -### RESERVOIR STORAGE COMMITMENT TESTS ## -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 144, 0, 24, 24, 48, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPLossLess HydroEnergyReservoir with HydroCommitmentReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 168, 0, 48, 48, 48, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Solving ED Hydro System using Dispatch Run of River" begin - sys = PSB.build_system(PSITestSystems, "c_sys5_hy") - networks = [ACPPowerModel, DCPPowerModel] - - test_results = Dict{Any, Float64}(ACPPowerModel => 177526.0, DCPPowerModel => 175521.0) - - for net in networks - @testset "HydroRoR ED model $(net)" begin - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroDispatch, HydroDispatchRunOfRiver) - ED = DecisionModel( - EconomicDispatchProblem, - template, - sys; - optimizer = ipopt_optimizer, - ) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == - PSI.BuildStatus.BUILT - psi_checksolve_test( - ED, - [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], - test_results[net], - 1000, - ) - end - end -end - -@testset "Solving ED Hydro System using Commitment Run of River" begin - sys = PSB.build_system(PSITestSystems, "c_sys5_hy") - net = DCPPowerModel - - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroDispatch, HydroCommitmentRunOfRiver) - - @testset "HydroRoR ED model $(net)" begin - ED = DecisionModel(UnitCommitmentProblem, template, sys; optimizer = GLPK_optimizer) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - psi_checksolve_test(ED, [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], 175521.0, 1000) - end -end - -@testset "Solving ED Hydro System using Dispatch with Reservoir" begin - systems = [ - PSB.build_system(PSITestSystems, "c_sys5_hyd"), - PSB.build_system(PSITestSystems, "c_sys5_hyd_ems"), - ] - networks = [ACPPowerModel, DCPPowerModel] - models = [HydroDispatchReservoirBudget, HydroDispatchReservoirStorage] - test_results = Dict{Any, Float64}( - (ACPPowerModel, HydroDispatchReservoirBudget) => 33423.0, - (DCPPowerModel, HydroDispatchReservoirBudget) => 33042.0, - (ACPPowerModel, HydroDispatchReservoirStorage) => 232497.0, - (DCPPowerModel, HydroDispatchReservoirStorage) => 230153.0, - ) - - for net in networks, (mod, sys) in zip(models, systems) - @testset "$(mod) ED model on $(net)" begin - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroEnergyReservoir, mod) - - ED = DecisionModel( - EconomicDispatchProblem, - template, - sys; - optimizer = ipopt_optimizer, - ) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == - PSI.BuildStatus.BUILT - psi_checksolve_test( - ED, - [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], - test_results[(net, mod)], - 10000, - ) - end - end -end - -@testset "Solving ED Hydro System using Commitment with Reservoir" begin - systems = [ - PSB.build_system(PSITestSystems, "c_sys5_hyd"), - PSB.build_system(PSITestSystems, "c_sys5_hyd_ems"), - ] - net = DCPPowerModel - models = [HydroCommitmentReservoirBudget, HydroCommitmentReservoirStorage] - test_results = Dict{Any, Float64}( - HydroCommitmentReservoirBudget => 33042.0, - HydroCommitmentReservoirStorage => 230153.0, - ) - - for (mod, sys) in zip(models, systems) - @testset "$(mod) ED model on $(net) and use_parameters = true" begin - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroEnergyReservoir, mod) - - ED = DecisionModel( - UnitCommitmentProblem, - template, - sys; - optimizer = GLPK_optimizer, - ) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == - PSI.BuildStatus.BUILT - psi_checksolve_test( - ED, - [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], - test_results[mod], - 10000, - ) - end - end -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1b-2b)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_b_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], 5621.0, 10.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1c-2c)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_c_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], 21.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1d-2d)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_d_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], -5429.0, 10.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1e-2e)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_e_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], 21.0, 10.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1f-2f)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_f_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], -17179.0) -end - -### Feedforward Test ### - -@testset "Test SemiContinuousFeedforward to HydroDispatch with HydroCommitmentRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - ff_sc = SemiContinuousFeedforward(; - component_type = HydroDispatch, - source = OnVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_sc) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 96, 0, 72, 48, 0, true) -end - -@testset "Test UpperBoundFeedforward to HydroDispatch with HydroCommitmentRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - ff_ub = UpperBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 96, 0, 72, 24, 0, true) -end - -@testset "Test LowerBoundFeedforward to HydroDispatch with HydroCommitmentRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - ff_ub = LowerBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 96, 0, 48, 48, 0, true) -end - -@testset "Test UpperBoundFeedforward to HydroDispatch with HydroDispatchRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - - ff_ub = UpperBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 72, 0, 72, 24, 0, false) -end - -@testset "Test LowerBoundFeedforward to HydroDispatch with HydroDispatchRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - - ff_ub = LowerBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 72, 0, 48, 48, 0, false) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir with HydroDispatchReservoirBudget model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirBudget) - ff_il = EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 72, 0, 27, 24, 0, false) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir with HydroDispatchReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - ff_il = EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 193, 0, 26, 24, 48, false) -end - -@testset "Test LowerBoundFeedforward to HydroEnergyReservoir with HydroDispatchReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - ff_il = LowerBoundFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 193, 0, 24, 48, 48, false) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir with HydroCommitmentReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - ff_il = EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ) - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 217, 0, 26, 24, 48, true) -end - -@testset "Test SemiContinuousFeedforward to HydroEnergyReservoir with HydroCommitmentReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - ff_sc = SemiContinuousFeedforward(; - component_type = HydroEnergyReservoir, - source = OnVariable, - affected_values = [ActivePowerVariable], - ) - PSI.attach_feedforward!(device_model, ff_sc) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 217, 0, 48, 48, 48, true) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir models" begin - device_model = DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage) - - ff_il = EnergyLimitFeedforward(; - component_type = HydroPumpedStorage, - source = ActivePowerOutVariable, - affected_values = [ActivePowerOutVariable], - number_of_periods = 12, - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 110, 0, 25, 24, 24, true) -end - -@testset "Test EnergyTargetFeedforward to HydroEnergyReservoir models" begin - device_model = DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage) - - ff_up = EnergyTargetFeedforward(; - component_type = HydroPumpedStorage, - source = EnergyVariableUp, - affected_values = [EnergyVariableUp], - target_period = 12, - penalty_cost = 1e4, - ) - - PSI.attach_feedforward!(device_model, ff_up) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 122, 0, 24, 25, 24, true) -end diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index 9c4100a19c..c264dd41ac 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -132,29 +132,6 @@ end moi_tests(model, 360, 0, 72, 120, 72, false) end -@testset "Test Reserves from Hydro" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, PowerLoad, StaticPowerLoad) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchRunOfRiver) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve5"), - ) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveDown}, RangeReserve, "Reserve6"), - ) - set_service_model!( - template, - ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), - ) - - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; add_reserves = true) - model = DecisionModel(template, c_sys5_hyd) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 240, 0, 48, 96, 72, false) -end - @testset "Test Reserves from with slack variables" begin template = get_thermal_dispatch_template_network( NetworkModel(CopperPlatePowerModel; use_slacks = true), From 952f3559fadf49ef5afdca5d6d094f3c112a5ce9 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 25 Apr 2023 13:59:51 -0600 Subject: [PATCH 010/370] move more code --- src/PowerSimulations.jl | 5 ++- src/core/formulations.jl | 2 +- test/test_simulation_build.jl | 84 ----------------------------------- 3 files changed, 4 insertions(+), 87 deletions(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 7b0705a91e..f2c45c3dd4 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -67,6 +67,9 @@ export ThermalCompactDispatch export DeviceLimitedRegulation export ReserveLimitedRegulation +###### Hydro ####### +export HydroDispatchRunOfRiver + # feedforward models export UpperBoundFeedforward export LowerBoundFeedforward @@ -525,7 +528,6 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") -include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") # Services Models @@ -547,7 +549,6 @@ include("initial_conditions/initialization.jl") # Device constructors include("devices_models/device_constructors/constructor_validations.jl") include("devices_models/device_constructors/thermalgeneration_constructor.jl") -include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 948289a0e0..4916aef959 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -78,7 +78,7 @@ abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ -struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end +struct HydroDispatchRunOfRiver <: AbstractHydroFormulation end ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end diff --git a/test/test_simulation_build.jl b/test/test_simulation_build.jl index 5acd725af5..b2fbe6589d 100644 --- a/test/test_simulation_build.jl +++ b/test/test_simulation_build.jl @@ -132,90 +132,6 @@ end @test_throws IS.ConflictingInputsError PSI._check_folder(sim) end -@testset "Multi-Stage Hydro Simulation Build" begin - sys_md = PSB.build_system(PSISystems, "5_bus_hydro_wk_sys") - - sys_uc = PSB.build_system(PSISystems, "5_bus_hydro_uc_sys") - transform_single_time_series!(sys_uc, 48, Hour(24)) - - sys_ed = PSB.build_system(PSISystems, "5_bus_hydro_ed_sys") - - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, ThermalStandard, ThermalBasicUnitCommitment) - set_device_model!(template, PowerLoad, StaticPowerLoad) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirBudget) - - template_uc = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template_uc, ThermalStandard, ThermalBasicUnitCommitment) - set_device_model!(template_uc, PowerLoad, StaticPowerLoad) - set_device_model!(template_uc, HydroEnergyReservoir, HydroDispatchRunOfRiver) - - template_ed = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template_ed, ThermalStandard, ThermalBasicUnitCommitment) - set_device_model!(template_ed, PowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchRunOfRiver) - - models = SimulationModels([ - DecisionModel( - template, - sys_md; - name = "MD", - initialize_model = false, - system_to_file = false, - optimizer = HiGHS_optimizer, - ), - DecisionModel( - template_uc, - sys_uc; - name = "UC", - initialize_model = false, - system_to_file = false, - optimizer = HiGHS_optimizer, - ), - DecisionModel( - template_ed, - sys_ed; - name = "ED", - initialize_model = false, - system_to_file = false, - optimizer = HiGHS_optimizer, - ), - ]) - - feedforwards = Dict( - "UC" => [ - EnergyLimitFeedforward(; - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - component_type = HydroEnergyReservoir, - number_of_periods = 24, - ), - ], - "ED" => [ - EnergyLimitFeedforward(; - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - component_type = HydroEnergyReservoir, - number_of_periods = 12, - ), - ], - ) - - test_sequence = SimulationSequence(; - models = models, - ini_cond_chronology = InterProblemChronology(), - feedforwards = feedforwards, - ) - - sim = Simulation(; - name = "test_md", - steps = 2, - models = models, - sequence = test_sequence, - simulation_folder = mktempdir(; cleanup = true), - ) - @test build!(sim; serialize = false) == PSI.BuildStatus.BUILT -end @testset "Test SemiContinuous Feedforward with Active and Reactive Power variables" begin template_uc = get_template_basic_uc_simulation() From 8ea8625b713d6133ed51ec7d75315e977f593652 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:35 -0700 Subject: [PATCH 011/370] bring back hydro constructors --- src/PowerSimulations.jl | 3 + src/core/formulations.jl | 9 +- .../hydrogeneration_constructor.jl | 468 ++++++++++++++++++ .../devices/hydro_generation.jl | 297 +++++++++++ 4 files changed, 776 insertions(+), 1 deletion(-) create mode 100644 src/devices_models/device_constructors/hydrogeneration_constructor.jl create mode 100644 src/devices_models/devices/hydro_generation.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index f2c45c3dd4..41a1f0c63b 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -69,6 +69,7 @@ export ReserveLimitedRegulation ###### Hydro ####### export HydroDispatchRunOfRiver +export HydroCommitmentRunOfRiver # feedforward models export UpperBoundFeedforward @@ -528,6 +529,7 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") +include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") # Services Models @@ -549,6 +551,7 @@ include("initial_conditions/initialization.jl") # Device constructors include("devices_models/device_constructors/constructor_validations.jl") include("devices_models/device_constructors/thermalgeneration_constructor.jl") +include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 4916aef959..7522280c51 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -74,11 +74,18 @@ struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end ############################ Hydro Generation Formulations ################################# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end +abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end +abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ -struct HydroDispatchRunOfRiver <: AbstractHydroFormulation end +struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end + +""" +Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` +""" +struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl new file mode 100644 index 0000000000..75673eba77 --- /dev/null +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -0,0 +1,468 @@ +""" +Construct model for HydroGen with FixedOutput Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) + + # Expression + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + return +end + +function construct_device!( + ::OptimizationContainer, + ::PSY.System, + ::ModelConstructStage, + ::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} + # FixedOutput doesn't add any constraints to the model. This function covers + # AbstractPowerModel and AbstractActivePowerModel + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + # Expression + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + return +end + +""" +Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractPowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, ReactivePowerVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractPowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_constraints!( + container, + ReactivePowerVariableLimitsConstraint, + ReactivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + add_constraint_dual!(container, sys, model) + + return +end + +""" +Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation +with only Active Power. +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end + +""" +Construct model for HydroGen with RunOfRiver Commitment Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, ReactivePowerVariable, devices, D()) + add_variables!(container, OnVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_constraints!( + container, + ReactivePowerVariableLimitsConstraint, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end + +""" +Construct model for HydroGen with RunOfRiver Commitment Formulation +with only Active Power. +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: HydroCommitmentRunOfRiver, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, OnVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: HydroCommitmentRunOfRiver, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl new file mode 100644 index 0000000000..69e861b2c7 --- /dev/null +++ b/src/devices_models/devices/hydro_generation.jl @@ -0,0 +1,297 @@ +#! format: off +requires_initialization(::AbstractHydroFormulation) = false +requires_initialization(::AbstractHydroUnitCommitment) = true + +get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 +get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB +get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB + +########################### ActivePowerVariable, HydroGen ################################# +get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false +get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 +get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max + +############## ActivePowerVariable, HydroDispatchRunOfRiver #################### +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 + +############## ReactivePowerVariable, HydroGen #################### +get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false +get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power(d) +get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).min +get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).max + +############## OnVariable, HydroGen #################### +get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true +get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 + +########################### Parameter related set functions ################################ +get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) +get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) + +get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 +get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 +get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max +get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min + +#################### Initial Conditions for models ############### +initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) +initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() +initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) +initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() +initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 +initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() +initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) +initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() + +########################Objective Function################################################## +proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 +proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) +proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_surplus_cost(cost) +proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_shortage_cost(cost) + +objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::EnergySurplusVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_NEGATIVE +objective_function_multiplier(::EnergyShortageVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE + +sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE +sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE + +variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 +variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) +variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) + +#! format: on + +function get_initial_conditions_device_model( + ::OperationModel, + model::DeviceModel{T, <:AbstractHydroFormulation}, +) where {T <: PSY.HydroEnergyReservoir} + return model +end + +function get_initial_conditions_device_model( + ::OperationModel, + ::DeviceModel{T, <:AbstractHydroFormulation}, +) where {T <: PSY.HydroDispatch} + return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) +end + +function get_default_time_series_names( + ::Type{<:PSY.HydroGen}, + ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, +) + return Dict{Type{<:TimeSeriesParameter}, String}( + ActivePowerTimeSeriesParameter => "max_active_power", + ReactivePowerTimeSeriesParameter => "max_active_power", + ) +end + +function get_default_attributes( + ::Type{T}, + ::Type{D}, +) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} + return Dict{String, Any}("reservation" => false) +end + +""" +Time series constraints +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + add_parameterized_upper_bound_range_constraints( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + U, + ActivePowerTimeSeriesParameter, + devices, + model, + X, + ) + return +end + +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:RangeConstraintLBExpressions}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + return +end + +""" +Add semicontinuous range constraints for Hydro Unit Commitment formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + return +end + +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + add_parameterized_upper_bound_range_constraints( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + U, + ActivePowerTimeSeriesParameter, + devices, + model, + X, + ) + return +end + +""" +Min and max reactive Power Variable limits +""" +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ReactivePowerVariableLimitsConstraint}, + ::Type{<:AbstractHydroFormulation}, +) + return PSY.get_reactive_power_limits(x) +end + +""" +Min and max active Power Variable limits +""" +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ActivePowerVariableLimitsConstraint}, + ::Type{<:AbstractHydroFormulation}, +) + return PSY.get_active_power_limits(x) +end + +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ActivePowerVariableLimitsConstraint}, + ::Type{HydroDispatchRunOfRiver}, +) + return (min = 0.0, max = PSY.get_max_active_power(x)) +end + +""" +Add power variable limits constraints for hydro unit commitment formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{<:PowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + return +end + +""" +Add power variable limits constraints for hydro dispatch formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{<:PowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where { + V <: PSY.HydroGen, + W <: AbstractHydroDispatchFormulation, + X <: PM.AbstractPowerModel, +} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + return +end + +##################################### Auxillary Variables ############################ +function _calculate_aux_variable_value!( + container::OptimizationContainer, + ::AuxVarKey{EnergyOutput, T}, + system::PSY.System, + p_variable_results::JuMPVariableArray, +) where {T <: PSY.HydroGen} + devices = axes(p_variable_results, 1) + time_steps = get_time_steps(container) + resolution = get_resolution(container) + fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR + aux_variable_container = get_aux_variable(container, EnergyOutput(), T) + for name in devices, t in time_steps + aux_variable_container[name, t] = + jump_value(p_variable_results[name, t]) * fraction_of_hour + end + + return +end + +function calculate_aux_variable_value!( + container::OptimizationContainer, + aux_key::AuxVarKey{EnergyOutput, T}, + system::PSY.System, +) where {T <: PSY.HydroGen} + p_variable_results = get_variable(container, ActivePowerVariable(), T) + _calculate_aux_variable_value!( + container, + aux_key, + system, + p_variable_results, + ) + return +end + +##################################### Hydro generation cost ############################ +function objective_function!( + container::OptimizationContainer, + devices::IS.FlattenIteratorWrapper{T}, + ::DeviceModel{T, U}, + ::Type{<:PM.AbstractPowerModel}, +) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} + add_variable_cost!(container, ActivePowerVariable(), devices, U()) + add_proportional_cost!(container, OnVariable(), devices, U()) + return +end + +function objective_function!( + container::OptimizationContainer, + devices::IS.FlattenIteratorWrapper{T}, + ::DeviceModel{T, U}, + ::Type{<:PM.AbstractPowerModel}, +) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} + add_variable_cost!(container, ActivePowerVariable(), devices, U()) + return +end From 505d63d6d8ec728c7abd652bb4c7e87d251a6e3a Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:42 -0700 Subject: [PATCH 012/370] bring back hydro tests --- ...st_device_hydro_generation_constructors.jl | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 test/test_device_hydro_generation_constructors.jl diff --git a/test/test_device_hydro_generation_constructors.jl b/test/test_device_hydro_generation_constructors.jl new file mode 100644 index 0000000000..7545c57ace --- /dev/null +++ b/test/test_device_hydro_generation_constructors.jl @@ -0,0 +1,121 @@ +################################### +###### FIXED OUTPUT TESTS ######### +################################### + +@testset "Hydro DCPLossLess FixedOutput" begin + device_model = DeviceModel(HydroDispatch, FixedOutput) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 0, 0, 0, 0, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with FixedOutput formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, FixedOutput) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 0, 0, 0, 0, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +################################### +### RUN OF RIVER DISPATCH TESTS ### +################################### + +@testset "Hydro DCPLossLess HydroDispatch with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 24, 0, 48, 24, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroDispatch with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 72, 48, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 24, 0, 48, 24, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 72, 48, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +################################### +#### RUN OF RIVER COMMIT TESTS #### +################################### + +@testset "Hydro DCPLossLess HydroDispatch with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 48, 24, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroDispatch with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 72, 0, 72, 48, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 48, 24, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 72, 0, 72, 48, 0, true) + psi_checkobjfun_test(model, GAEVF) +end From 6892059015222440f0a88e52b4d1b2f98a1a908c Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:57 -0700 Subject: [PATCH 013/370] remove reservoir budget from tests --- test/test_model_decision.jl | 62 ------------------ test/test_model_emulation.jl | 104 ------------------------------ test/test_print.jl | 7 -- test/test_services_constructor.jl | 23 +++++++ test/test_simulation_build.jl | 1 - test/test_simulation_execute.jl | 14 ---- test/test_simulation_results.jl | 11 +--- 7 files changed, 25 insertions(+), 197 deletions(-) diff --git a/test/test_model_decision.jl b/test/test_model_decision.jl index 12f3cb8074..3af76fc801 100644 --- a/test/test_model_decision.jl +++ b/test/test_model_decision.jl @@ -488,68 +488,6 @@ end HydroEnergyReservoir, ) @test solve!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroDispatchReservoirBudget ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; force_build = true) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirBudget) - model = DecisionModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test !PSI.has_initial_condition_value( - initial_conditions_data, - ActivePowerVariable(), - HydroEnergyReservoir, - ) - @test solve!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentReservoirBudget ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; force_build = true) - set_device_model!(template, HydroEnergyReservoir, HydroCommitmentReservoirBudget) - model = DecisionModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test PSI.has_initial_condition_value( - initial_conditions_data, - OnVariable(), - HydroEnergyReservoir, - ) - @test solve!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroDispatchReservoirStorage ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems"; force_build = true) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - model = DecisionModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test !PSI.has_initial_condition_value( - initial_conditions_data, - ActivePowerVariable(), - HydroEnergyReservoir, - ) - check_energy_initial_conditions_values(model, HydroEnergyReservoir) - @test solve!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentReservoirStorage ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems"; force_build = true) - set_device_model!(template, HydroEnergyReservoir, HydroCommitmentReservoirStorage) - model = DecisionModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test PSI.has_initial_condition_value( - initial_conditions_data, - OnVariable(), - HydroEnergyReservoir, - ) - check_energy_initial_conditions_values(model, HydroEnergyReservoir) - @test solve!(model) == RunStatus.SUCCESSFUL end @testset "Test serialization of InitialConditionsData" begin diff --git a/test/test_model_emulation.jl b/test/test_model_emulation.jl index ba40caa9ba..06baefcf7f 100644 --- a/test/test_model_emulation.jl +++ b/test/test_model_emulation.jl @@ -142,110 +142,6 @@ end HydroEnergyReservoir, ) @test run!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentRunOfRiver ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system( - PSITestSystems, - "c_sys5_hyd"; - add_single_time_series = true, - force_build = true, - ) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirBudget) - model = EmulationModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; executions = 10, output_dir = mktempdir(; cleanup = true)) == - BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test !PSI.has_initial_condition_value( - initial_conditions_data, - ActivePowerVariable(), - HydroEnergyReservoir, - ) - @test run!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentRunOfRiver ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system( - PSITestSystems, - "c_sys5_hyd"; - add_single_time_series = true, - force_build = true, - ) - set_device_model!(template, HydroEnergyReservoir, HydroCommitmentReservoirBudget) - model = EmulationModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; executions = 10, output_dir = mktempdir(; cleanup = true)) == - BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test PSI.has_initial_condition_value( - initial_conditions_data, - OnVariable(), - HydroEnergyReservoir, - ) - @test run!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentRunOfRiver ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system( - PSITestSystems, - "c_sys5_hyd_ems"; - add_single_time_series = true, - force_build = true, - ) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - model = EmulationModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; executions = 10, output_dir = mktempdir(; cleanup = true)) == - BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test !PSI.has_initial_condition_value( - initial_conditions_data, - ActivePowerVariable(), - HydroEnergyReservoir, - ) - ic_data = PSI.get_initial_condition( - PSI.get_optimization_container(model), - InitialEnergyLevel(), - HydroEnergyReservoir, - ) - for ic in ic_data - name = PSY.get_name(ic.component) - e_var = PSI.jump_value(PSI.get_value(ic)) - @test PSY.get_initial_storage(ic.component) == e_var - end - @test run!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentRunOfRiver ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system( - PSITestSystems, - "c_sys5_hyd_ems"; - add_single_time_series = true, - force_build = true, - ) - set_device_model!(template, HydroEnergyReservoir, HydroCommitmentReservoirStorage) - model = EmulationModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; executions = 10, output_dir = mktempdir(; cleanup = true)) == - BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test PSI.has_initial_condition_value( - initial_conditions_data, - OnVariable(), - HydroEnergyReservoir, - ) - ic_data = PSI.get_initial_condition( - PSI.get_optimization_container(model), - InitialEnergyLevel(), - HydroEnergyReservoir, - ) - for ic in ic_data - name = PSY.get_name(ic.component) - e_var = PSI.jump_value(PSI.get_value(ic)) - @test PSY.get_initial_storage(ic.component) == e_var - end - @test run!(model) == RunStatus.SUCCESSFUL end @testset "Emulation Model Results" begin diff --git a/test/test_print.jl b/test/test_print.jl index 43c154d02a..ff1e6108ea 100644 --- a/test/test_print.jl +++ b/test/test_print.jl @@ -45,7 +45,6 @@ end template_uc = get_template_basic_uc_simulation() template_ed = get_template_nomin_ed_simulation() set_device_model!(template_ed, InterruptiblePowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchReservoirBudget) set_network_model!(template_uc, NetworkModel( CopperPlatePowerModel, # MILP "duals" not supported with free solvers @@ -88,12 +87,6 @@ end source = OnVariable, affected_values = [ActivePowerVariable], ), - EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ), ], ), ini_cond_chronology = InterProblemChronology(), diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index c264dd41ac..9c4100a19c 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -132,6 +132,29 @@ end moi_tests(model, 360, 0, 72, 120, 72, false) end +@testset "Test Reserves from Hydro" begin + template = ProblemTemplate(CopperPlatePowerModel) + set_device_model!(template, PowerLoad, StaticPowerLoad) + set_device_model!(template, HydroEnergyReservoir, HydroDispatchRunOfRiver) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve5"), + ) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveDown}, RangeReserve, "Reserve6"), + ) + set_service_model!( + template, + ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), + ) + + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; add_reserves = true) + model = DecisionModel(template, c_sys5_hyd) + @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT + moi_tests(model, 240, 0, 48, 96, 72, false) +end + @testset "Test Reserves from with slack variables" begin template = get_thermal_dispatch_template_network( NetworkModel(CopperPlatePowerModel; use_slacks = true), diff --git a/test/test_simulation_build.jl b/test/test_simulation_build.jl index b2fbe6589d..5bda0fa750 100644 --- a/test/test_simulation_build.jl +++ b/test/test_simulation_build.jl @@ -132,7 +132,6 @@ end @test_throws IS.ConflictingInputsError PSI._check_folder(sim) end - @testset "Test SemiContinuous Feedforward with Active and Reactive Power variables" begin template_uc = get_template_basic_uc_simulation() set_network_model!(template_uc, NetworkModel(DCPPowerModel; use_slacks = true)) diff --git a/test/test_simulation_execute.jl b/test/test_simulation_execute.jl index 783c4c5241..f50bab178f 100644 --- a/test/test_simulation_execute.jl +++ b/test/test_simulation_execute.jl @@ -38,7 +38,6 @@ function test_2_stage_decision_models_with_feedforwards(in_memory) template_uc = get_template_basic_uc_simulation() template_ed = get_template_nomin_ed_simulation() set_device_model!(template_ed, InterruptiblePowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchReservoirBudget) set_network_model!(template_uc, NetworkModel( CopperPlatePowerModel, # MILP "duals" not supported with free solvers @@ -80,12 +79,6 @@ function test_2_stage_decision_models_with_feedforwards(in_memory) source = OnVariable, affected_values = [ActivePowerVariable], ), - EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ), ], ), ini_cond_chronology = InterProblemChronology(), @@ -128,7 +121,6 @@ end ), ) set_device_model!(template_ed, InterruptiblePowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchReservoirBudget) c_sys5_hy_uc = PSB.build_system(PSITestSystems, "c_sys5_hy_uc") c_sys5_hy_ed = PSB.build_system(PSITestSystems, "c_sys5_hy_ed") models = SimulationModels(; @@ -157,12 +149,6 @@ end source = OnVariable, affected_values = [ActivePowerVariable], ), - EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ), ], ), ini_cond_chronology = InterProblemChronology(), diff --git a/test/test_simulation_results.jl b/test/test_simulation_results.jl index 98525c9302..4b8816d043 100644 --- a/test/test_simulation_results.jl +++ b/test/test_simulation_results.jl @@ -132,7 +132,6 @@ function test_simulation_results(file_path::String, export_path; in_memory = fal template_uc = get_template_basic_uc_simulation() template_ed = get_template_nomin_ed_simulation() set_device_model!(template_ed, InterruptiblePowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchReservoirBudget) set_network_model!( template_uc, NetworkModel(CopperPlatePowerModel; duals = [CopperPlateBalanceConstraint]), @@ -173,12 +172,6 @@ function test_simulation_results(file_path::String, export_path; in_memory = fal source = OnVariable, affected_values = [ActivePowerVariable], ), - EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ), ], ), ini_cond_chronology = InterProblemChronology(), @@ -230,7 +223,7 @@ function test_simulation_results(file_path::String, export_path; in_memory = fal verify_export_results(results, export_path) - @test length(readdir(export_realized_results(results_ed))) === 18 + @test length(readdir(export_realized_results(results_ed))) === 17 # Test that you can't read a failed simulation. PSI.set_simulation_status!(sim, RunStatus.FAILED) @@ -547,7 +540,7 @@ function test_emulation_problem_results(results::SimulationResults, in_memory) ) == 10 parameters_keys = collect(keys(read_realized_parameters(results_em))) - @test length(parameters_keys) == 7 + @test length(parameters_keys) == 5 parameters_inputs = ( [ "ActivePowerTimeSeriesParameter__PowerLoad", From 6ca556ef26169ef95a82c7467c1a69c0cc0870b8 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 13:04:52 -0700 Subject: [PATCH 014/370] bring back hydro docs --- docs/make.jl | 1 + docs/src/formulation_library/General.md | 2 +- docs/src/formulation_library/HydroGen.md | 134 +++++++++++++++++++++++ 3 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 docs/src/formulation_library/HydroGen.md diff --git a/docs/make.jl b/docs/make.jl index f2ec3aaedb..0fc90a93a8 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -30,6 +30,7 @@ pages = OrderedDict( "Formulation Library" => Any[ "General" => "formulation_library/General.md", "Thermal Generation" => "formulation_library/ThermalGen.md", + "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", diff --git a/docs/src/formulation_library/General.md b/docs/src/formulation_library/General.md index 8b69c0803a..e5912b268c 100644 --- a/docs/src/formulation_library/General.md +++ b/docs/src/formulation_library/General.md @@ -29,7 +29,7 @@ using PowerSystems using DataFrames using Latexify combo_tables = [] -for t in [RenewableGen, ThermalGen, ElectricLoad] +for t in [RenewableGen, ThermalGen, HydroGen, ElectricLoad] combos = PowerSimulations.get_default_time_series_names(t, FixedOutput) combo_table = DataFrame( "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md new file mode 100644 index 0000000000..efe13982b3 --- /dev/null +++ b/docs/src/formulation_library/HydroGen.md @@ -0,0 +1,134 @@ +# `PowerSystems.HydroGen` Formulations + +Valid `DeviceModel`s for subtypes of `HydroGen` include the following: + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.generate_device_formulation_combinations() +filter!(x -> x["device_type"] <: HydroGen, combos) +combo_table = DataFrame( + "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], + "Device Type" => ["[$(c["device_type"])](https://nrel-siip.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], + "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], + ) +mdtable(combo_table, latex = false) +``` + +--- + +## `HydroDispatchRunOfRiver` + +```@docs +HydroDispatchRunOfRiver +``` + +**Variables:** + +- [`ActivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_active_power(device)` +- [`ReactivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_reactive_power(device)` + +**Static Parameters:** + +- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` +- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` +- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` + +**Time Series Parameters:** + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroDispatchRunOfRiver) +combo_table = DataFrame( + "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), + "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), + ) +mdtable(combo_table, latex = false) +``` + +**Objective:** + +Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg``. + +**Expressions:** + +Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) + +**Constraints:** + +```math +\begin{aligned} +& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ +& Qg^\text{min} \le Qg_t \le Qg^\text{max} +\end{aligned} +``` + +--- + +## `HydroCommitmentRunOfRiver` + +```@docs +HydroCommitmentRunOfRiver +``` + +**Variables:** + +- [`ActivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_active_power(device)` +- [`ReactivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_reactive_power(device)` +- [`OnVariable`](@ref): + - Bounds: {0, 1} + - Default initial value: `PowerSystems.get_status(device)` + +**Static Parameters:** + +- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` +- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` +- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` + +**Time Series Parameters:** + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroCommitmentRunOfRiver) +combo_table = DataFrame( + "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), + "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), + ) +mdtable(combo_table, latex = false) +``` + +**Objective:** + +Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. + +**Expressions:** + +Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) + +**Constraints:** + +```math +\begin{aligned} +& Pg_t \le Pg^\text{max}\\ +& Pg_t - u_t Pg^\text{max} \le 0 \\ +& Pg_t - u_t Pg^\text{min} \ge 0 \\ +& Qg_t - u_t Qg^\text{max} \le 0 \\ +& Qg_t - u_t Qg^\text{min} \ge 0 +\end{aligned} +``` \ No newline at end of file From 55e4aafbc82135287f803b994ac32d35203ee243 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 17 May 2023 15:45:16 -0700 Subject: [PATCH 015/370] add script for debug --- scripts/debug_emulation_psi.jl | 74 ++++++++++++++++++++ src/operation/operation_problem_templates.jl | 2 +- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 scripts/debug_emulation_psi.jl diff --git a/scripts/debug_emulation_psi.jl b/scripts/debug_emulation_psi.jl new file mode 100644 index 0000000000..779169427a --- /dev/null +++ b/scripts/debug_emulation_psi.jl @@ -0,0 +1,74 @@ +using Pkg +Pkg.activate("test") +Pkg.instantiate() +using Revise + + +using PowerSimulations +using PowerSystems +using PowerSystemCaseBuilder +using InfrastructureSystems +const PSY = PowerSystems +const PSI = PowerSimulations +const PSB = PowerSystemCaseBuilder +using Xpress +using JuMP +using Logging +using Dates +using TimeSeries + +c_sys5_reg = PSB.build_system(PSITestSystems, "c_sys5_reg") + +# Transform Deterministic to Static +load_dict = Dict() +for load in get_components(PowerLoad, c_sys5_reg) + name = get_name(load) + t_array = get_time_series_array( + Deterministic, + load, + "max_active_power", + start_time = DateTime("2024-01-01T00:00:00"), + ) + load_dict[name] = collect(values(t_array)) +end + +reg_dict = Dict() +for dev in get_components(RegulationDevice, c_sys5_reg) + name = get_name(dev) + t_array = get_time_series_array( + Deterministic, + dev, + "max_active_power", + start_time = DateTime("2024-01-01T00:00:00"), + ) + reg_dict[name] = collect(values(t_array)) +end + +remove_time_series!(c_sys5_reg, Deterministic) + +resolution = Dates.Hour(1) +dates = range(DateTime("2024-01-01T00:00:00"), step = resolution, length = 24) +c_sys5_reg + +for load in get_components(PowerLoad, c_sys5_reg) + name = get_name(load) + t_array = load_dict[name] + data = TimeArray(dates, t_array) + ts = SingleTimeSeries("max_active_power", data) + add_time_series!(c_sys5_reg, load, ts) +end + +for dev in get_components(RegulationDevice, c_sys5_reg) + name = get_name(dev) + t_array = reg_dict[name] + data = TimeArray(dates, t_array) + ts = SingleTimeSeries("max_active_power", data) + add_time_series!(c_sys5_reg, dev, ts) +end + + +template_agc = template_agc_reserve_deployment() +model = EmulationModel(template_agc, c_sys5_reg; optimizer = Xpress.Optimizer) +build!(model; executions = 24, output_dir = mktempdir(; cleanup = true)) + +run!(model) \ No newline at end of file diff --git a/src/operation/operation_problem_templates.jl b/src/operation/operation_problem_templates.jl index 5a60c03c52..0d714a118c 100644 --- a/src/operation/operation_problem_templates.jl +++ b/src/operation/operation_problem_templates.jl @@ -130,6 +130,6 @@ function template_agc_reserve_deployment(; kwargs...) ReserveLimitedRegulation, ), ) - set_service_model!(template, ServiceModel(PSY.AGC, PIDSmoothACE)) + set_service_model!(template, ServiceModel(PSY.AGC, PIDSmoothACE, "AGC_Area1")) return template end From 0efacc8e507a1a2125c396b2a4ff48d02bbde0b4 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 17 May 2023 18:29:27 -0700 Subject: [PATCH 016/370] add debug script --- scripts/debug_emulation_psi.jl | 60 ++++++++++++++++------------------ 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/scripts/debug_emulation_psi.jl b/scripts/debug_emulation_psi.jl index 779169427a..c58dee29b0 100644 --- a/scripts/debug_emulation_psi.jl +++ b/scripts/debug_emulation_psi.jl @@ -3,7 +3,6 @@ Pkg.activate("test") Pkg.instantiate() using Revise - using PowerSimulations using PowerSystems using PowerSystemCaseBuilder @@ -22,53 +21,52 @@ c_sys5_reg = PSB.build_system(PSITestSystems, "c_sys5_reg") # Transform Deterministic to Static load_dict = Dict() for load in get_components(PowerLoad, c_sys5_reg) - name = get_name(load) - t_array = get_time_series_array( - Deterministic, - load, - "max_active_power", - start_time = DateTime("2024-01-01T00:00:00"), - ) - load_dict[name] = collect(values(t_array)) + name = get_name(load) + t_array = get_time_series_array( + Deterministic, + load, + "max_active_power"; + start_time = DateTime("2024-01-01T00:00:00"), + ) + load_dict[name] = collect(values(t_array)) end reg_dict = Dict() for dev in get_components(RegulationDevice, c_sys5_reg) - name = get_name(dev) - t_array = get_time_series_array( - Deterministic, - dev, - "max_active_power", - start_time = DateTime("2024-01-01T00:00:00"), - ) - reg_dict[name] = collect(values(t_array)) + name = get_name(dev) + t_array = get_time_series_array( + Deterministic, + dev, + "max_active_power"; + start_time = DateTime("2024-01-01T00:00:00"), + ) + reg_dict[name] = collect(values(t_array)) end remove_time_series!(c_sys5_reg, Deterministic) resolution = Dates.Hour(1) -dates = range(DateTime("2024-01-01T00:00:00"), step = resolution, length = 24) +dates = range(DateTime("2024-01-01T00:00:00"); step = resolution, length = 24) c_sys5_reg for load in get_components(PowerLoad, c_sys5_reg) - name = get_name(load) - t_array = load_dict[name] - data = TimeArray(dates, t_array) - ts = SingleTimeSeries("max_active_power", data) - add_time_series!(c_sys5_reg, load, ts) + name = get_name(load) + t_array = load_dict[name] + data = TimeArray(dates, t_array) + ts = SingleTimeSeries("max_active_power", data) + add_time_series!(c_sys5_reg, load, ts) end for dev in get_components(RegulationDevice, c_sys5_reg) - name = get_name(dev) - t_array = reg_dict[name] - data = TimeArray(dates, t_array) - ts = SingleTimeSeries("max_active_power", data) - add_time_series!(c_sys5_reg, dev, ts) + name = get_name(dev) + t_array = reg_dict[name] + data = TimeArray(dates, t_array) + ts = SingleTimeSeries("max_active_power", data) + add_time_series!(c_sys5_reg, dev, ts) end - template_agc = template_agc_reserve_deployment() model = EmulationModel(template_agc, c_sys5_reg; optimizer = Xpress.Optimizer) -build!(model; executions = 24, output_dir = mktempdir(; cleanup = true)) +build!(model; executions = 23, output_dir = mktempdir(; cleanup = true)) -run!(model) \ No newline at end of file +run!(model) From 826d0f11c3d1fc08c334af1da132cfe9c1a82702 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 17 May 2023 18:29:48 -0700 Subject: [PATCH 017/370] update constructor to change some variables to be indexed by AGC --- src/services_models/services_constructor.jl | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index ecd2a46453..abd18bee05 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -242,18 +242,18 @@ function construct_service!( if !isempty(setdiff(areas, agc_areas)) throw( IS.ConflictingInputsError( - "All area most have an AGC service assigned in order to model the System's Frequency regulation", + "All area must have an AGC service assigned in order to model the System's Frequency regulation", ), ) end add_variables!(container, SteadyStateFrequencyDeviation) - add_variables!(container, AreaMismatchVariable, areas, T()) - add_variables!(container, SmoothACE, areas, T()) - add_variables!(container, LiftVariable, areas, T()) + add_variables!(container, AreaMismatchVariable, services, T()) + add_variables!(container, SmoothACE, services, T()) + add_variables!(container, LiftVariable, services, T()) add_variables!(container, ActivePowerVariable, areas, T()) - add_variables!(container, DeltaActivePowerUpVariable, areas, T()) - add_variables!(container, DeltaActivePowerDownVariable, areas, T()) + add_variables!(container, DeltaActivePowerUpVariable, services, T()) + add_variables!(container, DeltaActivePowerDownVariable, services, T()) add_variables!(container, AdditionalDeltaActivePowerUpVariable, areas, T()) add_variables!(container, AdditionalDeltaActivePowerDownVariable, areas, T()) @@ -292,12 +292,12 @@ function construct_service!( areas = PSY.get_components(PSY.Area, sys) services = get_available_components(S, sys) - add_constraints!(container, AbsoluteValueConstraint, LiftVariable, areas, model) + add_constraints!(container, AbsoluteValueConstraint, LiftVariable, services, model) add_constraints!( container, FrequencyResponseConstraint, SteadyStateFrequencyDeviation, - areas, + services, model, sys, ) @@ -305,17 +305,17 @@ function construct_service!( container, SACEPIDAreaConstraint, SteadyStateFrequencyDeviation, - areas, + services, model, sys, ) - add_constraints!(container, BalanceAuxConstraint, SmoothACE, areas, model, sys) + add_constraints!(container, BalanceAuxConstraint, SmoothACE, services, model, sys) add_feedforward_constraints!(container, model, services) add_constraint_dual!(container, sys, model) - objective_function!(container, areas, model) + objective_function!(container, services, model) return end From 2ac43c4767ff43fc8e672b99bfbbedd75c72d392 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 17 May 2023 18:30:02 -0700 Subject: [PATCH 018/370] add name to default template --- src/operation/operation_problem_templates.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operation/operation_problem_templates.jl b/src/operation/operation_problem_templates.jl index 0d714a118c..5a60c03c52 100644 --- a/src/operation/operation_problem_templates.jl +++ b/src/operation/operation_problem_templates.jl @@ -130,6 +130,6 @@ function template_agc_reserve_deployment(; kwargs...) ReserveLimitedRegulation, ), ) - set_service_model!(template, ServiceModel(PSY.AGC, PIDSmoothACE, "AGC_Area1")) + set_service_model!(template, ServiceModel(PSY.AGC, PIDSmoothACE)) return template end From 337b37ec7c2653b4a4ba056eaf85fb32d512079e Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 17 May 2023 18:30:24 -0700 Subject: [PATCH 019/370] add update initial condition for mismatch variable --- .../initial_conditions_update_in_memory_store.jl | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/operation/initial_conditions_update_in_memory_store.jl b/src/operation/initial_conditions_update_in_memory_store.jl index b8767a273c..165606124e 100644 --- a/src/operation/initial_conditions_update_in_memory_store.jl +++ b/src/operation/initial_conditions_update_in_memory_store.jl @@ -113,3 +113,17 @@ function update_initial_conditions!( end return end + +function update_initial_conditions!( + ics::Vector{T}, + store::EmulationModelStore, + ::Dates.Millisecond, +) where { + T <: InitialCondition{AreaControlError, S}, +} where {S <: Union{Float64, JuMP.VariableRef}} + for ic in ics + var_val = get_variable_value(store, AreaMismatchVariable(), get_component_type(ic)) + set_ic_quantity!(ic, get_last_recorded_value(var_val)[get_component_name(ic)]) + end + return +end From a963e4c206ef4cf40a1de2d94752ac3eb5393f49 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 17 May 2023 18:30:42 -0700 Subject: [PATCH 020/370] update objective function to dispatch per AGC --- src/devices_models/devices/common/objective_functions.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices_models/devices/common/objective_functions.jl b/src/devices_models/devices/common/objective_functions.jl index 87bf5faca2..a0981f39b8 100644 --- a/src/devices_models/devices/common/objective_functions.jl +++ b/src/devices_models/devices/common/objective_functions.jl @@ -123,9 +123,9 @@ end function add_proportional_cost!( container::OptimizationContainer, ::U, - areas::IS.FlattenIteratorWrapper{T}, + agcs::IS.FlattenIteratorWrapper{T}, ::PIDSmoothACE, -) where {T <: PSY.Area, U <: LiftVariable} +) where {T <: PSY.AGC, U <: LiftVariable} lift_variable = get_variable(container, U(), T) for index in Iterators.product(axes(lift_variable)...) add_to_objective_invariant_expression!( From 766c6ad233806805077998d44e5a3637c98b4410 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 17 May 2023 18:31:00 -0700 Subject: [PATCH 021/370] update expression to dispatch per agc --- src/devices_models/devices/common/add_to_expression.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index ba24c91f15..6de54d3235 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1004,15 +1004,15 @@ function add_to_expression!( V <: PSY.AGC, W <: AbstractServiceFormulation, } - names = [PSY.get_name(PSY.get_area(s)) for s in services] + names = PSY.get_name.(services) time_steps = get_time_steps(container) if !has_container_key(container, T, V) - expression = add_expression_container!(container, T(), PSY.Area, names, time_steps) + expression = add_expression_container!(container, T(), PSY.AGC, names, time_steps) end - expression = get_expression(container, T(), PSY.Area) - variable = get_variable(container, U(), PSY.Area) + expression = get_expression(container, T(), PSY.AGC) + variable = get_variable(container, U(), PSY.AGC) for s in services, t in time_steps - name = PSY.get_name(PSY.get_area(s)) + name = PSY.get_name(s) _add_to_jump_expression!( expression[name, t], variable[t], From 0a2608b513a139896fc7141d96dad55049703c03 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 17 May 2023 18:33:28 -0700 Subject: [PATCH 022/370] update reg device to dispatch using both area and agc --- src/devices_models/devices/regulation_device.jl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/devices_models/devices/regulation_device.jl b/src/devices_models/devices/regulation_device.jl index e8aa37ed72..aba9df5a68 100644 --- a/src/devices_models/devices/regulation_device.jl +++ b/src/devices_models/devices/regulation_device.jl @@ -180,8 +180,8 @@ function add_constraints!( R_dn = get_variable(container, DeltaActivePowerDownVariable(), T) R_up_emergency = get_variable(container, AdditionalDeltaActivePowerUpVariable(), T) R_dn_emergency = get_variable(container, AdditionalDeltaActivePowerUpVariable(), T) - area_reserve_up = get_variable(container, DeltaActivePowerUpVariable(), PSY.Area) - area_reserve_dn = get_variable(container, DeltaActivePowerDownVariable(), PSY.Area) + area_reserve_up = get_variable(container, DeltaActivePowerUpVariable(), PSY.AGC) + area_reserve_dn = get_variable(container, DeltaActivePowerDownVariable(), PSY.AGC) component_names = [PSY.get_name(d) for d in devices] participation_assignment_up = add_constraints_container!( @@ -208,9 +208,11 @@ function add_constraints!( services = PSY.get_services(d) if length(services) > 1 device_agc = (a for a in PSY.get_services(d) if isa(a, PSY.AGC)) + agc_name = PSY.get_name.(device_agc)[1] area_name = PSY.get_name.(PSY.get_area.(device_agc))[1] else device_agc = first(services) + agc_name = PSY.get_name(device_agc) area_name = PSY.get_name(PSY.get_area(device_agc)) end p_factor = PSY.get_participation_factor(d) @@ -218,12 +220,12 @@ function add_constraints!( participation_assignment_up[name, t] = JuMP.@constraint( container.JuMPmodel, R_up[name, t] == - (p_factor.up * area_reserve_up[area_name, t]) + R_up_emergency[name, t] + (p_factor.up * area_reserve_up[agc_name, t]) + R_up_emergency[name, t] ) participation_assignment_dn[name, t] = JuMP.@constraint( container.JuMPmodel, R_dn[name, t] == - (p_factor.dn * area_reserve_dn[area_name, t]) + R_dn_emergency[name, t] + (p_factor.dn * area_reserve_dn[agc_name, t]) + R_dn_emergency[name, t] ) JuMP.add_to_expression!(expr_up[area_name, t], -1 * R_up_emergency[name, t]) JuMP.add_to_expression!(expr_dn[area_name, t], -1 * R_dn_emergency[name, t]) From 354a6196c8d42479b826d3d2bf1b964c70c53b64 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 17 May 2023 18:33:36 -0700 Subject: [PATCH 023/370] update agc device model --- src/services_models/agc.jl | 118 ++++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 54 deletions(-) diff --git a/src/services_models/agc.jl b/src/services_models/agc.jl index 3de0ddffdf..0746b53840 100644 --- a/src/services_models/agc.jl +++ b/src/services_models/agc.jl @@ -1,25 +1,25 @@ #! format: off -get_variable_multiplier(_, ::Type{<:PSY.Area}, ::AbstractAGCFormulation) = NaN -########################## ActivePowerVariable, Area ########################### +get_variable_multiplier(_, ::Type{<:PSY.AGC}, ::AbstractAGCFormulation) = NaN +########################## ActivePowerVariable, AGC ########################### ########################## SteadyStateFrequencyDeviation ################################## -get_variable_binary(::SteadyStateFrequencyDeviation, ::Type{<:PSY.Area}, ::AbstractAGCFormulation) = false +get_variable_binary(::SteadyStateFrequencyDeviation, ::Type{<:PSY.AGC}, ::AbstractAGCFormulation) = false get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.Area}, ::AbstractAGCFormulation) = false - ########################## SmoothACE, AggregationTopology ########################### get_variable_binary(::SmoothACE, ::Type{<:PSY.AggregationTopology}, ::AbstractAGCFormulation) = false +get_variable_binary(::SmoothACE, ::Type{<:PSY.AGC}, ::AbstractAGCFormulation) = false -########################## DeltaActivePowerUpVariable, Area ########################### +########################## DeltaActivePowerUpVariable, AGC ########################### -get_variable_binary(::DeltaActivePowerUpVariable, ::Type{<:PSY.Area}, ::AbstractAGCFormulation) = false -get_variable_lower_bound(::DeltaActivePowerUpVariable, ::PSY.Area, ::AbstractAGCFormulation) = 0.0 +get_variable_binary(::DeltaActivePowerUpVariable, ::Type{<:PSY.AGC}, ::AbstractAGCFormulation) = false +get_variable_lower_bound(::DeltaActivePowerUpVariable, ::PSY.AGC, ::AbstractAGCFormulation) = 0.0 -########################## DeltaActivePowerDownVariable, Area ########################### +########################## DeltaActivePowerDownVariable, AGC ########################### -get_variable_binary(::DeltaActivePowerDownVariable, ::Type{<:PSY.Area}, ::AbstractAGCFormulation) = false -get_variable_lower_bound(::DeltaActivePowerDownVariable, ::PSY.Area, ::AbstractAGCFormulation) = 0.0 +get_variable_binary(::DeltaActivePowerDownVariable, ::Type{<:PSY.AGC}, ::AbstractAGCFormulation) = false +get_variable_lower_bound(::DeltaActivePowerDownVariable, ::PSY.AGC, ::AbstractAGCFormulation) = 0.0 ########################## AdditionalDeltaPowerUpVariable, Area ########################### @@ -31,12 +31,12 @@ get_variable_lower_bound(::AdditionalDeltaActivePowerUpVariable, ::PSY.Area, ::A get_variable_binary(::AdditionalDeltaActivePowerDownVariable, ::Type{<:PSY.Area}, ::AbstractAGCFormulation) = false get_variable_lower_bound(::AdditionalDeltaActivePowerDownVariable, ::PSY.Area, ::AbstractAGCFormulation) = 0.0 -########################## AreaMismatchVariable, Area ########################### -get_variable_binary(::AreaMismatchVariable, ::Type{<:PSY.Area}, ::AbstractAGCFormulation) = false +########################## AreaMismatchVariable, AGC ########################### +get_variable_binary(::AreaMismatchVariable, ::Type{<:PSY.AGC}, ::AbstractAGCFormulation) = false ########################## LiftVariable, Area ########################### -get_variable_binary(::LiftVariable, ::Type{<:PSY.Area}, ::AbstractAGCFormulation) = false -get_variable_lower_bound(::LiftVariable, ::PSY.Area, ::AbstractAGCFormulation) = 0.0 +get_variable_binary(::LiftVariable, ::Type{<:PSY.AGC}, ::AbstractAGCFormulation) = false +get_variable_lower_bound(::LiftVariable, ::PSY.AGC, ::AbstractAGCFormulation) = 0.0 initial_condition_default(::AreaControlError, d::PSY.AGC, ::AbstractAGCFormulation) = PSY.get_initial_ace(d) initial_condition_variable(::AreaControlError, d::PSY.AGC, ::AbstractAGCFormulation) = AreaMismatchVariable() @@ -53,7 +53,7 @@ function add_variables!( ::Type{T}, ) where {T <: SteadyStateFrequencyDeviation} time_steps = get_time_steps(container) - variable = add_variable_container!(container, T(), PSY.Area, time_steps) + variable = add_variable_container!(container, T(), PSY.AGC, time_steps) for t in time_steps variable[t] = JuMP.@variable(container.JuMPmodel, base_name = "ΔF_{$(t)}") end @@ -74,20 +74,20 @@ function add_constraints!( container::OptimizationContainer, ::Type{T}, ::Type{LiftVariable}, - areas::IS.FlattenIteratorWrapper{U}, + agcs::IS.FlattenIteratorWrapper{U}, ::ServiceModel{PSY.AGC, V}, -) where {T <: AbsoluteValueConstraint, U <: PSY.Area, V <: PIDSmoothACE} +) where {T <: AbsoluteValueConstraint, U <: PSY.AGC, V <: PIDSmoothACE} time_steps = get_time_steps(container) - area_names = PSY.get_name.(areas) + agc_names = PSY.get_name.(agcs) container_lb = - add_constraints_container!(container, T(), U, area_names, time_steps; meta = "lb") + add_constraints_container!(container, T(), U, agc_names, time_steps; meta = "lb") container_ub = - add_constraints_container!(container, T(), U, area_names, time_steps; meta = "ub") + add_constraints_container!(container, T(), U, agc_names, time_steps; meta = "ub") mismatch = get_variable(container, AreaMismatchVariable(), U) z = get_variable(container, LiftVariable(), U) jump_model = get_jump_model(container) - for t in time_steps, a in area_names + for t in time_steps, a in agc_names container_lb[a, t] = JuMP.@constraint(jump_model, mismatch[a, t] <= z[a, t]) container_ub[a, t] = JuMP.@constraint(jump_model, -1 * mismatch[a, t] <= z[a, t]) end @@ -102,15 +102,16 @@ function add_constraints!( container::OptimizationContainer, ::Type{T}, ::Type{SteadyStateFrequencyDeviation}, - areas::IS.FlattenIteratorWrapper{U}, + agcs::IS.FlattenIteratorWrapper{U}, ::ServiceModel{PSY.AGC, V}, sys::PSY.System, -) where {T <: FrequencyResponseConstraint, U <: PSY.Area, V <: PIDSmoothACE} +) where {T <: FrequencyResponseConstraint, U <: PSY.AGC, V <: PIDSmoothACE} time_steps = get_time_steps(container) - area_names = PSY.get_name.(areas) + agc_names = PSY.get_name.(agcs) frequency_response = 0.0 - for area in PSY.get_components(PSY.Area, sys) + for agc in PSY.get_components(x -> x.available, PSY.AGC, sys) + area = PSY.get_area(agc) frequency_response += PSY.get_load_response(area) end @@ -125,22 +126,26 @@ function add_constraints!( # This value is the one updated later in simulation based on the UC result inv_frequency_reponse = 1 / frequency_response - area_balance = get_variable(container, ActivePowerVariable(), U) + area_balance = get_variable(container, ActivePowerVariable(), PSY.Area) frequency = get_variable(container, SteadyStateFrequencyDeviation(), U) R_up = get_variable(container, DeltaActivePowerUpVariable(), U) R_dn = get_variable(container, DeltaActivePowerDownVariable(), U) - R_up_emergency = get_variable(container, AdditionalDeltaActivePowerUpVariable(), U) - R_dn_emergency = get_variable(container, AdditionalDeltaActivePowerUpVariable(), U) + R_up_emergency = + get_variable(container, AdditionalDeltaActivePowerUpVariable(), PSY.Area) + R_dn_emergency = + get_variable(container, AdditionalDeltaActivePowerUpVariable(), PSY.Area) const_container = add_constraints_container!(container, T(), PSY.System, time_steps) for t in time_steps system_balance = sum(area_balance.data[:, t]) - for a in area_names + for agc in agcs + a = PSY.get_name(agc) + area_name = PSY.get_name(PSY.get_area(agc)) JuMP.add_to_expression!(system_balance, R_up[a, t]) JuMP.add_to_expression!(system_balance, -1 * R_dn[a, t]) - JuMP.add_to_expression!(system_balance, R_up_emergency[a, t]) - JuMP.add_to_expression!(system_balance, -1 * R_dn_emergency[a, t]) + JuMP.add_to_expression!(system_balance, R_up_emergency[area_name, t]) + JuMP.add_to_expression!(system_balance, -1 * R_dn_emergency[area_name, t]) end const_container[t] = JuMP.@constraint( container.JuMPmodel, @@ -154,12 +159,13 @@ function add_constraints!( container::OptimizationContainer, ::Type{T}, ::Type{SteadyStateFrequencyDeviation}, - areas::IS.FlattenIteratorWrapper{U}, + agcs::IS.FlattenIteratorWrapper{U}, ::ServiceModel{PSY.AGC, V}, sys::PSY.System, -) where {T <: SACEPIDAreaConstraint, U <: PSY.Area, V <: PIDSmoothACE} +) where {T <: SACEPIDAreaConstraint, U <: PSY.AGC, V <: PIDSmoothACE} services = get_available_components(PSY.AGC, sys) time_steps = get_time_steps(container) + agc_names = PSY.get_name.(services) area_names = [PSY.get_name(PSY.get_area(s)) for s in services] RAW_ACE = get_expression(container, RawACE(), U) SACE = get_variable(container, SmoothACE(), U) @@ -167,7 +173,7 @@ function add_constraints!( container, SACEPIDAreaConstraint(), U, - area_names, + agc_names, time_steps, ) @@ -177,7 +183,7 @@ function add_constraints!( ki = PSY.get_K_i(service) kd = PSY.get_K_d(service) Δt = convert(Dates.Second, container.resolution).value - a = PSY.get_name(PSY.get_area(service)) + a = PSY.get_name(service) for t in time_steps if t == 1 ACE_ini = get_initial_condition(container, AreaControlError(), PSY.AGC)[ix] @@ -203,46 +209,50 @@ function add_constraints!( container::OptimizationContainer, ::Type{T}, ::Type{SmoothACE}, - areas::IS.FlattenIteratorWrapper{U}, + agcs::IS.FlattenIteratorWrapper{U}, ::ServiceModel{PSY.AGC, V}, sys::PSY.System, -) where {T <: BalanceAuxConstraint, U <: PSY.Area, V <: PIDSmoothACE} +) where {T <: BalanceAuxConstraint, U <: PSY.AGC, V <: PIDSmoothACE} time_steps = get_time_steps(container) - area_names = PSY.get_name.(areas) + agc_names = PSY.get_name.(agcs) aux_equation = add_constraints_container!( container, BalanceAuxConstraint(), PSY.System, - area_names, + agc_names, time_steps, ) - area_mismatch = get_variable(container, AreaMismatchVariable(), PSY.Area) - SACE = get_variable(container, SmoothACE(), PSY.Area) - R_up = get_variable(container, DeltaActivePowerUpVariable(), PSY.Area) - R_dn = get_variable(container, DeltaActivePowerDownVariable(), PSY.Area) + area_mismatch = get_variable(container, AreaMismatchVariable(), PSY.AGC) + SACE = get_variable(container, SmoothACE(), PSY.AGC) + R_up = get_variable(container, DeltaActivePowerUpVariable(), PSY.AGC) + R_dn = get_variable(container, DeltaActivePowerDownVariable(), PSY.AGC) R_up_emergency = get_variable(container, AdditionalDeltaActivePowerUpVariable(), PSY.Area) R_dn_emergency = get_variable(container, AdditionalDeltaActivePowerUpVariable(), PSY.Area) - for t in time_steps, a in area_names - aux_equation[a, t] = JuMP.@constraint( - container.JuMPmodel, - -1 * SACE[a, t] == - (R_up[a, t] - R_dn[a, t]) + - (R_up_emergency[a, t] - R_dn_emergency[a, t]) + - area_mismatch[a, t] - ) + for t in time_steps + for agc in agcs + a = PSY.get_name(agc) + area_name = PSY.get_name(PSY.get_area(agc)) + aux_equation[a, t] = JuMP.@constraint( + container.JuMPmodel, + -1 * SACE[a, t] == + (R_up[a, t] - R_dn[a, t]) + + (R_up_emergency[area_name, t] - R_dn_emergency[area_name, t]) + + area_mismatch[a, t] + ) + end end return end function objective_function!( container::OptimizationContainer, - areas::IS.FlattenIteratorWrapper{T}, + agcs::IS.FlattenIteratorWrapper{T}, ::ServiceModel{<:PSY.AGC, U}, -) where {T <: PSY.Area, U <: PIDSmoothACE} - add_proportional_cost!(container, LiftVariable(), areas, U()) +) where {T <: PSY.AGC, U <: PIDSmoothACE} + add_proportional_cost!(container, LiftVariable(), agcs, U()) return end From cf694339228ad30be16564b078c200cb66aa469a Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 19 May 2023 17:01:30 -0700 Subject: [PATCH 024/370] update agc model --- src/services_models/agc.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services_models/agc.jl b/src/services_models/agc.jl index 0746b53840..70821f8842 100644 --- a/src/services_models/agc.jl +++ b/src/services_models/agc.jl @@ -110,7 +110,7 @@ function add_constraints!( agc_names = PSY.get_name.(agcs) frequency_response = 0.0 - for agc in PSY.get_components(x -> x.available, PSY.AGC, sys) + for agc in agcs area = PSY.get_area(agc) frequency_response += PSY.get_load_response(area) end From f5719db9c8f96428e31cabe3a55fca07370955da Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 19 May 2023 17:01:39 -0700 Subject: [PATCH 025/370] update rts --- scripts/create_rts_systems.jl | 376 ++++++++++++++++++++++++++++++++ scripts/rts_simulation_setup.jl | 155 +++++++++++++ scripts/script_utils.jl | 73 +++++++ scripts/test_emulation_psi.jl | 72 ++++++ 4 files changed, 676 insertions(+) create mode 100644 scripts/create_rts_systems.jl create mode 100644 scripts/rts_simulation_setup.jl create mode 100644 scripts/script_utils.jl create mode 100644 scripts/test_emulation_psi.jl diff --git a/scripts/create_rts_systems.jl b/scripts/create_rts_systems.jl new file mode 100644 index 0000000000..ae4d33d819 --- /dev/null +++ b/scripts/create_rts_systems.jl @@ -0,0 +1,376 @@ +using Pkg +Pkg.activate("test") +Pkg.instantiate() +using Revise + +using PowerSimulations +using PowerSystems +using PowerSystemCaseBuilder +using InfrastructureSystems +const PSY = PowerSystems +const PSI = PowerSimulations +const PSB = PowerSystemCaseBuilder +using Xpress +using JuMP +using Logging +using Dates +using TimeSeries +using Random +rng = MersenneTwister(1234) +using Interpolations +using Distributions + +sys_DA = PSB.build_RTS_GMLC_DA_sys_noTS(; raw_data = PSB.RTS_DIR) +sys_RT = PSB.build_RTS_GMLC_RT_sys_noTS(; raw_data = PSB.RTS_DIR) +sys_RT_HourAhead = PSB.build_RTS_GMLC_RT_sys_noTS(; raw_data = PSB.RTS_DIR) + +reserve_hydro = true # use false to remove hydro from the reserve provision devices + +area_maps_regup = Dict() +area_maps_regup["1"] = "Reg_Up_R1" +area_maps_regup["2"] = "Reg_Up_R2" +area_maps_regup["3"] = "Reg_Up_R3" + +area_maps_regdn = Dict() +area_maps_regdn["1"] = "Reg_Down_R1" +area_maps_regdn["2"] = "Reg_Down_R2" +area_maps_regdn["3"] = "Reg_Down_R3" + +area_maps_spin = Dict() +area_maps_spin["1"] = "Spin_Up_R1" +area_maps_spin["2"] = "Spin_Up_R2" +area_maps_spin["3"] = "Spin_Up_R3" + +for sys in [sys_DA, sys_RT, sys_RT_HourAhead] + # Adjust Reserve Provisions + # Remove Flex Reserves + res_up = get_component(VariableReserve{ReserveUp}, sys, "Flex_Up") + if !isnothing(res_up) + remove_component!(sys, res_up) + end + res_dn = get_component(VariableReserve{ReserveDown}, sys, "Flex_Down") + if !isnothing(res_dn) + remove_component!(sys, res_dn) + end + mult = 1.0 + # Reg Up Split + reg_reserve_up = get_component(VariableReserve, sys, "Reg_Up") + set_requirement!(reg_reserve_up, mult * get_requirement(reg_reserve_up)) + for name in ["Reg_Up_R1", "Reg_Up_R2", "Reg_Up_R3"] + reg_zone = PSY.VariableReserve{ReserveUp}(; + name = name, + available = true, + time_frame = reg_reserve_up.time_frame, + requirement = reg_reserve_up.requirement / 3.0, + ) + old_ts = get_time_series(SingleTimeSeries, reg_reserve_up, "requirement") + add_component!(sys, reg_zone) + add_time_series!(sys, reg_zone, old_ts) + end + remove_component!(sys, reg_reserve_up) + # Reg Down Split + reg_reserve_dn = get_component(VariableReserve, sys, "Reg_Down") + set_requirement!(reg_reserve_dn, mult * get_requirement(reg_reserve_dn)) + for name in ["Reg_Down_R1", "Reg_Down_R2", "Reg_Down_R3"] + reg_zone = PSY.VariableReserve{ReserveDown}(; + name = name, + available = true, + time_frame = reg_reserve_dn.time_frame, + requirement = reg_reserve_dn.requirement / 3.0, + ) + old_ts = get_time_series(SingleTimeSeries, reg_reserve_dn, "requirement") + add_component!(sys, reg_zone) + add_time_series!(sys, reg_zone, old_ts) + end + remove_component!(sys, reg_reserve_dn) + + spin_reserve_R1 = get_component(VariableReserve, sys, "Spin_Up_R1") + spin_reserve_R2 = get_component(VariableReserve, sys, "Spin_Up_R2") + spin_reserve_R3 = get_component(VariableReserve, sys, "Spin_Up_R3") + + for g in get_components(Generator, sys) + clear_services!(g) + end + # Remove Destillate Fuel from sys and update services + for g in get_components( + x -> x.prime_mover in [PrimeMovers.CT, PrimeMovers.CC], + ThermalStandard, + sys, + ) + if get_fuel(g) == ThermalFuels.DISTILLATE_FUEL_OIL + remove_component!(sys, g) + continue + end + g.operation_cost.shut_down = g.operation_cost.start_up / 2.0 + + #= + # Small generators do not participate in reg + if PSY.get_base_power(g) > 3.0 + clear_services!(g) + add_service!(g, reg_reserve_dn) + add_service!(g, reg_reserve_up) + continue + end + =# + area_name = get_name(get_area(get_bus(g))) + reg_up = get_component(VariableReserve, sys, area_maps_regup[area_name]) + reg_dn = get_component(VariableReserve, sys, area_maps_regdn[area_name]) + add_service!(g, reg_up, sys) + add_service!(g, reg_dn, sys) + + # Update costs to avoid degenerate solutions in thermal + if get_prime_mover(g) == PrimeMovers.CT + set_status!(g, false) + set_active_power!(g, 0.0) + old_pwl_array = get_variable(get_operation_cost(g)) |> get_cost + new_pwl_array = similar(old_pwl_array) + for (ix, tup) in enumerate(old_pwl_array) + if ix ∈ [1, length(old_pwl_array)] + cost_noise = 50.0 * rand() + new_pwl_array[ix] = ((tup[1] + cost_noise), tup[2]) + else + try_again = true + while try_again + cost_noise = 50.0 * rand() + power_noise = 0.01 * rand() + slope_previous = + ((tup[1] + cost_noise) - old_pwl_array[ix - 1][1]) / + ((tup[2] - power_noise) - old_pwl_array[ix - 1][2]) + slope_next = + (-(tup[1] + cost_noise) + old_pwl_array[ix + 1][1]) / + (-(tup[2] - power_noise) + old_pwl_array[ix + 1][2]) + new_pwl_array[ix] = ((tup[1] + cost_noise), (tup[2] - power_noise)) + try_again = slope_previous > slope_next + end + end + end + get_variable(get_operation_cost(g)).cost = new_pwl_array + end + end + + for g in get_components( + x -> !(x.prime_mover in [PrimeMovers.CT, PrimeMovers.CC]), + ThermalStandard, + sys, + ) + get_operation_cost(g).shut_down = get_operation_cost(g).start_up / 2.0 + area_name = get_name(get_area(get_bus(g))) + reg_up = get_component(VariableReserve, sys, area_maps_regup[area_name]) + reg_dn = get_component(VariableReserve, sys, area_maps_regdn[area_name]) + reg_spin = get_component(VariableReserve, sys, area_maps_spin[area_name]) + if !(get_fuel(g) == ThermalFuels.NUCLEAR) + add_service!(g, reg_up, sys) + add_service!(g, reg_dn, sys) + add_service!(g, reg_spin, sys) + end + end + + #= + for g in get_components(RenewableDispatch, sys) + set_operation_cost!(g, TwoPartCost(0.0, 0.0)) + area_name = get_name(get_area(get_bus(g))) + reg_up = get_component(VariableReserve, sys, area_maps_regup[area_name]) + reg_dn = get_component(VariableReserve, sys, area_maps_regdn[area_name]) + reg_spin = get_component(VariableReserve, sys, area_maps_spin[area_name]) + add_service!(g, reg_up, sys) + add_service!(g, reg_dn, sys) + add_service!(g, reg_spin, sys) + end + =# + + for g in get_components(HydroEnergyReservoir, sys) + area_name = get_name(get_area(get_bus(g))) + reg_up = get_component(VariableReserve, sys, area_maps_regup[area_name]) + reg_dn = get_component(VariableReserve, sys, area_maps_regdn[area_name]) + reg_spin = get_component(VariableReserve, sys, area_maps_spin[area_name]) + add_service!(g, reg_up, sys) + add_service!(g, reg_dn, sys) + add_service!(g, reg_spin, sys) + end + + #Remove units that make no sense to include + names = [ + "114_SYNC_COND_1", + "314_SYNC_COND_1", + "313_STORAGE_1", + "214_SYNC_COND_1", + "212_CSP_1", + ] + for d in get_components(x -> x.name ∈ names, Generator, sys) + remove_component!(sys, d) + end + for br in get_components(DCBranch, sys) + remove_component!(sys, br) + end + for d in get_components(Storage, sys) + remove_component!(sys, d) + end + + # Update Ramp Limits + for d in + get_components(x -> (occursin(r"STEAM|NUCLEAR", get_name(x))), ThermalStandard, sys) + + #get_fuel(d) == ThermalFuels.COAL && set_ramp_limits!(d, (up = 0.001, down = 0.001)) + + #if get_rating(d) < 3.0 + # set_status!(d, false) + # clear_services!(d) + #reserve_hydro && add_service!(d, reg_reserve_up) + #reserve_hydro && add_service!(d, reg_reserve_dn) + #add_service!(d, spin_reserve_R1, sys) + # set_active_power!(d, 0.0) + # continue + #end + get_operation_cost(d).shut_down = get_operation_cost(d).start_up / 2.0 + if get_fuel(d) == ThermalFuels.NUCLEAR + set_ramp_limits!(d, (up = 0.0, down = 0.0)) + set_time_limits!(d, (up = 4380.0, down = 4380.0)) + end + end + + # Remove bad Hydro + for d in get_components(HydroDispatch, sys) + remove_component!(sys, d) + end + + #= + for area in get_components(Area, sys) + if get_name(area) == "1" + continue + end + remove_component!(sys, area) + end + for b in get_components(Bus, sys) + set_area!(b, get_component(Area, sys, "1")) + end + =# +end + +horizon_DA = 48 +interval_DA = Hour(24) +horizon_RT = 24 +interval_RT = Minute(5) +horizon_HourAhead = 24 +interval_HourAhead = Hour(1) + +transform_single_time_series!(sys_DA, horizon_DA, interval_DA) +transform_single_time_series!(sys_RT, horizon_RT, interval_RT) +transform_single_time_series!(sys_RT_HourAhead, horizon_HourAhead, interval_HourAhead) + +to_json(sys_DA, "data/sys_DA_1h.json"; force = true) +to_json(sys_RT, "data/sys_RT_5min.json"; force = true) +to_json(sys_RT_HourAhead, "data/sys_RT_HourAhead_2hours.json"; force = true) + +########################################################################################## +################################## Here AGC code starts ################################## +########################################################################################## + +sys_AGC = deepcopy(sys_RT) +remove_time_series!(sys_AGC, DeterministicSingleTimeSeries) +remove_time_series!(sys_AGC, SingleTimeSeries) + +init_time = DateTime("2020-01-01T00:00:00") +final_time = DateTime("2020-12-31T23:59:56") +end_time = DateTime("2020-12-31T23:55:00") + +for type in [RenewableFix, ElectricLoad] + for d in get_components(type, sys_RT) + @show get_name(d) + for l in get_time_series_names(SingleTimeSeries, d) + step_time = Minute(5) + step_range = Int(Minute(5) / Second(4)) + _dates = range(init_time, final_time; step = Second(4)) + time_series = get_time_series(SingleTimeSeries, d, l) + total_interp_timeseries = Vector{Float64}(undef, size(_dates)[1]) + current_date = init_time + i = 0 + while current_date < end_time + t_stamps = range(current_date; step = Second(4), length = step_range) + val_init = values(time_series[current_date].data)[1] + val_next = values(time_series[current_date + step_time].data)[1] + _vals = range(1, 2; length = step_range) + interp_vals = LinearInterpolation(1:2, [val_init, val_next])(_vals) + if type <: ElectricLoad + noise = rand(Normal(0.0, 0.025), step_range) + else + noise = rand(Normal(0.0, 0.1), step_range) + end + interp_vals .+= noise + total_interp_timeseries[(i * step_range + 1):((i + 1) * step_range)] = + interp_vals + current_date += step_time + i = i + 1 + end + data = TimeArray(_dates, max.(total_interp_timeseries, 0.0)) + ts = SingleTimeSeries(l, data) + c = get_component(typeof(d), sys_AGC, get_name(d)) + add_time_series!(sys_AGC, c, ts) + end + end +end + +#= +for g in get_components(ThermalStandard, sys_AGC) + _date = DateTime("2020-09-01") + step_time = Hour(1) + current_date = deepcopy(_date) + while current_date < DateTime("2020-09-11") + t_stamps = range(current_date, step = Second(4), length = 900) + vals = zeros(length(t_stamps)) + forecast = Deterministic("get_rating", TimeArray(t_stamps, vals)) + add_forecast!(sys_AGC, g, forecast) + current_date += step_time + end +end + +for g in get_components(RenewableDispatch, sys_AGC) + _date = DateTime("2020-09-01") + step_time = Hour(1) + current_date = deepcopy(_date) + while current_date < DateTime("2020-09-11") + t_stamps = range(current_date, step = Second(4), length = 900) + vals = zeros(length(t_stamps)) + forecast = Deterministic("get_rating", TimeArray(t_stamps, vals)) + add_forecast!(sys_AGC, g, forecast) + current_date += step_time + end +end +=# + +for area in get_components(Area, sys_AGC) + AGC_service = PSY.AGC(; + name = "AGC_Area_$(area)", + available = true, + bias = 739.0, + K_p = 2.5 + rand(Normal(0.0, 0.025), 1)[1], + K_i = max(0.1 + rand(Normal(0.0, 0.00025), 1)[1], 0.001), + K_d = 0.0, + delta_t = 4, + area = get_component(Area, sys_AGC, get_name(area)), + ) + + contributing_devices = Vector{PSY.Device}() + reg_reserve_up = + get_component(VariableReserve, sys_AGC, area_maps_regup[get_name(area)]) + for g in get_components(x -> x.bus.area == area, Generator, sys_AGC) + if has_service(g, reg_reserve_up) + droop = if isa(g, ThermalStandard) + 0.04 * PSY.get_base_power(g) + else + 0.05 * PSY.get_base_power(g) + end + p_factor = (up = 1.0, dn = 1.0) + t = RegulationDevice(g; participation_factor = p_factor, droop = droop) + add_component!(sys_AGC, t) + push!(contributing_devices, t) + end + end + + add_service!(sys_AGC, AGC_service, contributing_devices) +end + +for res in get_components(VariableReserve, sys_AGC) + remove_component!(sys_AGC, res) +end + +to_json(sys_AGC, "data/sys_AGC_4sec.json"; force = true) diff --git a/scripts/rts_simulation_setup.jl b/scripts/rts_simulation_setup.jl new file mode 100644 index 0000000000..c56efda8c7 --- /dev/null +++ b/scripts/rts_simulation_setup.jl @@ -0,0 +1,155 @@ +using Pkg +Pkg.activate("test") +Pkg.instantiate() +using Revise + +using PowerSimulations +using PowerSystems +using PowerSystemCaseBuilder +using InfrastructureSystems +const PSY = PowerSystems +const PSI = PowerSimulations +const PSB = PowerSystemCaseBuilder +using Xpress +using JuMP +using Logging +using Dates +using TimeSeries + +include("script_utils.jl") + +sys_DA = System("data/sys_DA_1h.json") +sys_RT = System("data/sys_RT_5min.json") + +mipgap = 1e-2 # 1% +num_steps = 30 +starttime = DateTime("2020-01-01T00:00:00") + +template_uc = get_uc_ptdf_template(sys_DA) +set_device_model!(template_uc, ThermalStandard, ThermalBasicUnitCommitment) +template_ed = get_ed_ptdf_template(sys_RT) +set_device_model!(template_ed, ThermalStandard, ThermalBasicDispatch) + +models = SimulationModels(; + decision_models = [ + DecisionModel( + template_uc, + sys_DA; + name = "UC", + optimizer = optimizer_with_attributes(Xpress.Optimizer, "MIPRELSTOP" => mipgap), + system_to_file = false, + initialize_model = true, + optimizer_solve_log_print = false, + direct_mode_optimizer = true, + rebuild_model = false, + store_variable_names = true, + calculate_conflict = true, + ), + DecisionModel( + template_ed, + sys_RT; + name = "ED", + optimizer = optimizer_with_attributes(Xpress.Optimizer, "MIPRELSTOP" => mipgap), + system_to_file = false, + initialize_model = true, + optimizer_solve_log_print = false, + direct_mode_optimizer = true, + rebuild_model = false, + store_variable_names = true, + calculate_conflict = true, + ), + ], +) + +# Set-up the sequence UC-ED +sequence = SimulationSequence(; + models = models, + feedforwards = Dict( + "ED" => [ + SemiContinuousFeedforward(; + component_type = ThermalStandard, + source = OnVariable, + affected_values = [ActivePowerVariable], + ), + FixValueFeedforward(; + component_type = VariableReserve{ReserveUp}, + source = ActivePowerReserveVariable, + affected_values = [ActivePowerReserveVariable], + ), + FixValueFeedforward(; + component_type = VariableReserve{ReserveDown}, + source = ActivePowerReserveVariable, + affected_values = [ActivePowerReserveVariable], + ), + ], + ), + ini_cond_chronology = InterProblemChronology(), +) + +sim = Simulation(; + name = "compact_sim", + steps = num_steps, + models = models, + sequence = sequence, + initial_time = starttime, + simulation_folder = mktempdir(; cleanup = true), +) + +build!(sim; console_level = Logging.Info, serialize = false) +execute!(sim; enable_progress_bar = true); + +uc = sim.models.decision_models[1] +ed = sim.models.decision_models[2] +vars = ed.internal.container.variables +pwl = vars[PSI.VariableKey{PSI.PieceWiseLinearCostVariable, ThermalStandard}("")] +pwl_var = pwl["315_STEAM_1", 1, 1] +p = vars[PSI.VariableKey{ActivePowerVariable, ThermalStandard}("")] +p["315_STEAM_1", 1] +p_stuff = p["315_STEAM_1", :] +p_vals = value.(p_stuff) +value.(regup["324_PV_3", :]) + +param = ed.internal.container.parameters +on_val = param[PSI.ParameterKey{OnStatusParameter, ThermalStandard}("")].parameter_array +regup3 = + param[PSI.ParameterKey{FixValueParameter, VariableReserve{ReserveUp}}( + "Reg_Up_R3", + )].parameter_array +spinup3 = + param[PSI.ParameterKey{FixValueParameter, VariableReserve{ReserveUp}}( + "Spin_Up_R3", + )].parameter_array +regdown3 = + param[PSI.ParameterKey{FixValueParameter, VariableReserve{ReserveDown}}( + "Reg_Down_R3", + )].parameter_array +regup3["315_STEAM_1", :] +regdown3["315_STEAM_1", :] +spinup3["315_STEAM_1", :] +on_val_steam = JuMP.fix_value.(on_val["315_STEAM_1", :]) + +g = get_component(ThermalStandard, sys_RT, "315_STEAM_1") +g.bus + +var_state = sim.internal.simulation_state.decision_states.variables +on_state = var_state[PSI.VariableKey{OnVariable, ThermalStandard}("")] +regup_state3 = + var_state[PSI.VariableKey{ActivePowerReserveVariable, VariableReserve{ReserveDown}}( + "Reg_Down_R3", + )] +reg_val = regup_state3.values[!, "315_STEAM_1"] + +constr = ed.internal.container.constraints +ub_ff = constr[PSI.ConstraintKey{FeedforwardSemiContinousConstraint, ThermalStandard}( + "ActivePowerVariable_ub", +)] +ub_ff["315_STEAM_1", :] + +#= +Name Type Sense Bound +R3217 row LE .0000000:00:00 +C4 column LO .000000 +C1598 column UP .000000 +C10643 column LO 1.000000 +C11317 column LO 1.000000 +=# diff --git a/scripts/script_utils.jl b/scripts/script_utils.jl new file mode 100644 index 0000000000..91220bddfb --- /dev/null +++ b/scripts/script_utils.jl @@ -0,0 +1,73 @@ +############################### +###### Model Templates ######## +############################### + +# Some models are commented for RTS model + +function set_uc_models!(template_uc) + set_device_model!(template_uc, ThermalStandard, ThermalStandardUnitCommitment) + set_device_model!(template_uc, RenewableDispatch, RenewableFullDispatch) + set_device_model!(template_uc, RenewableFix, FixedOutput) + set_device_model!(template_uc, PowerLoad, StaticPowerLoad) + set_device_model!(template_uc, TapTransformer, StaticBranchUnbounded) + set_device_model!(template_uc, HydroEnergyReservoir, HydroDispatchRunOfRiver) + set_service_model!( + template_uc, + ServiceModel(VariableReserve{ReserveUp}, RangeReserve; use_slacks = true), + ) + set_service_model!( + template_uc, + ServiceModel(VariableReserve{ReserveDown}, RangeReserve; use_slacks = true), + ) + return +end + +############################### +###### Get Templates ########## +############################### + +### PTDF Bounded #### + +function get_uc_ptdf_template(sys) + template_uc = ProblemTemplate( + NetworkModel( + StandardPTDFModel; + use_slacks = false, + PTDF_matrix = PTDF(sys), + duals = [CopperPlateBalanceConstraint], + ), + ) + set_uc_models!(template_uc) + set_device_model!(template_uc, Line, StaticBranch) + return template_uc +end + +function get_ed_ptdf_template(sys) + template_ed = ProblemTemplate( + NetworkModel( + StandardPTDFModel; + use_slacks = true, + PTDF_matrix = PTDF(sys), + duals = [CopperPlateBalanceConstraint], + ), + ) + set_uc_models!(template_ed) + set_device_model!(template_ed, ThermalStandard, ThermalStandardDispatch) + return template_ed +end + +#### PTDF Unbounded #### + +function get_uc_ptdf_unbounded_template(sys) + template_uc = get_uc_ptdf_template(sys) + set_device_model!(template_uc, Line, StaticBranchUnbounded) + return template_uc +end + +function get_ed_ptdf_unbounded_template(sys_rts_rt) + template_ed = get_ed_ptdf_template(sys_rts_rt) + set_device_model!(template_uc, Line, StaticBranchUnbounded) + return template_ed +end + +####### Simulations ##### diff --git a/scripts/test_emulation_psi.jl b/scripts/test_emulation_psi.jl new file mode 100644 index 0000000000..c58dee29b0 --- /dev/null +++ b/scripts/test_emulation_psi.jl @@ -0,0 +1,72 @@ +using Pkg +Pkg.activate("test") +Pkg.instantiate() +using Revise + +using PowerSimulations +using PowerSystems +using PowerSystemCaseBuilder +using InfrastructureSystems +const PSY = PowerSystems +const PSI = PowerSimulations +const PSB = PowerSystemCaseBuilder +using Xpress +using JuMP +using Logging +using Dates +using TimeSeries + +c_sys5_reg = PSB.build_system(PSITestSystems, "c_sys5_reg") + +# Transform Deterministic to Static +load_dict = Dict() +for load in get_components(PowerLoad, c_sys5_reg) + name = get_name(load) + t_array = get_time_series_array( + Deterministic, + load, + "max_active_power"; + start_time = DateTime("2024-01-01T00:00:00"), + ) + load_dict[name] = collect(values(t_array)) +end + +reg_dict = Dict() +for dev in get_components(RegulationDevice, c_sys5_reg) + name = get_name(dev) + t_array = get_time_series_array( + Deterministic, + dev, + "max_active_power"; + start_time = DateTime("2024-01-01T00:00:00"), + ) + reg_dict[name] = collect(values(t_array)) +end + +remove_time_series!(c_sys5_reg, Deterministic) + +resolution = Dates.Hour(1) +dates = range(DateTime("2024-01-01T00:00:00"); step = resolution, length = 24) +c_sys5_reg + +for load in get_components(PowerLoad, c_sys5_reg) + name = get_name(load) + t_array = load_dict[name] + data = TimeArray(dates, t_array) + ts = SingleTimeSeries("max_active_power", data) + add_time_series!(c_sys5_reg, load, ts) +end + +for dev in get_components(RegulationDevice, c_sys5_reg) + name = get_name(dev) + t_array = reg_dict[name] + data = TimeArray(dates, t_array) + ts = SingleTimeSeries("max_active_power", data) + add_time_series!(c_sys5_reg, dev, ts) +end + +template_agc = template_agc_reserve_deployment() +model = EmulationModel(template_agc, c_sys5_reg; optimizer = Xpress.Optimizer) +build!(model; executions = 23, output_dir = mktempdir(; cleanup = true)) + +run!(model) From b75b4d40601753295b455fb39d7a84dd989fdb17 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 12:25:19 -0600 Subject: [PATCH 026/370] use reserves in reserve models --- src/services_models/reserves.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/services_models/reserves.jl b/src/services_models/reserves.jl index cbc1251d3f..33988203cc 100644 --- a/src/services_models/reserves.jl +++ b/src/services_models/reserves.jl @@ -37,7 +37,7 @@ uses_compact_power(::PSY.ReserveDemandCurve, ::StepwiseCostReserve)=false function get_initial_conditions_service_model( ::OperationModel, ::ServiceModel{T, D}, -) where {T <: PSY.Service, D <: AbstractServiceFormulation} +) where {T <: PSY.Reserve, D <: AbstractReservesFormulation} return ServiceModel(T, D) end @@ -60,13 +60,13 @@ function get_default_time_series_names( end function get_default_time_series_names( - ::Type{<:PSY.Service}, - ::Type{<:AbstractServiceFormulation}, + ::Type{<:PSY.Reserve}, + ::Type{<:AbstractReservesFormulation}, ) return Dict{Type{<:TimeSeriesParameter}, String}() end -function get_default_attributes(::Type{<:PSY.Service}, ::Type{<:AbstractServiceFormulation}) +function get_default_attributes(::Type{<:PSY.Reserve}, ::Type{<:AbstractReservesFormulation}) return Dict{String, Any}() end From 1d566137a9e68bfd67f31ecf327af892c7887b71 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 12:25:29 -0600 Subject: [PATCH 027/370] add interface formulations --- src/PowerSimulations.jl | 3 +++ src/core/formulations.jl | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index b1e31398f6..5155090bf9 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -35,6 +35,8 @@ export StepwiseCostReserve export NonSpinningReserve export PIDSmoothACE export GroupReserve +export ConstantMaxInterfaceFlow + ######## Branch Models ######## export StaticBranch export StaticBranchBounds @@ -539,6 +541,7 @@ include("devices_models/devices/regulation_device.jl") # Services Models include("services_models/agc.jl") include("services_models/reserves.jl") +include("services_models/transmission_interface.jl") include("services_models/group_reserve.jl") include("services_models/service_slacks.jl") include("services_models/services_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index dedffc553a..5b09ff9405 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -246,3 +246,5 @@ struct RangeReserve <: AbstractReservesFormulation end struct StepwiseCostReserve <: AbstractReservesFormulation end struct RampReserve <: AbstractReservesFormulation end struct NonSpinningReserve <: AbstractReservesFormulation end + +struct ConstantMaxInterfaceFlow <: AbstractServiceFormulation end From 90b1ea4bc7099caf4a53a3910ad4712e75e3550d Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:55:57 -0600 Subject: [PATCH 028/370] add new expression types --- src/core/expressions.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/expressions.jl b/src/core/expressions.jl index 89c6a8df15..ab981f4f45 100644 --- a/src/core/expressions.jl +++ b/src/core/expressions.jl @@ -47,9 +47,12 @@ struct ReserveRangeExpressionUB <: RangeConstraintUBExpressions end struct ComponentActivePowerRangeExpressionUB <: RangeConstraintUBExpressions end struct ComponentReserveUpBalanceExpression <: ExpressionType end struct ComponentReserveDownBalanceExpression <: ExpressionType end +struct InterfaceTotalFlow <: ExpressionType end should_write_resulting_value(::Type{<:ExpressionType}) = false should_write_resulting_value(::Type{<:CostExpressions}) = true +should_write_resulting_value(::Type{InterfaceTotalFlow}) = true should_write_resulting_value(::Type{RawACE}) = true convert_result_to_natural_units(::Type{<:ExpressionType}) = false +convert_result_to_natural_units(::Type{InterfaceTotalFlow}) = true From 516be7841e80c1fa5445f3ecbcaead094fbde4ee Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:56:05 -0600 Subject: [PATCH 029/370] remove stale code --- .../constructor_validations.jl | 55 ------------------- 1 file changed, 55 deletions(-) diff --git a/src/devices_models/device_constructors/constructor_validations.jl b/src/devices_models/device_constructors/constructor_validations.jl index 50fd4a3bff..dbf142ae00 100644 --- a/src/devices_models/device_constructors/constructor_validations.jl +++ b/src/devices_models/device_constructors/constructor_validations.jl @@ -10,58 +10,3 @@ function validate_available_devices( PSY.check_components(system, devices) return true end - -function validate_service!( - model::ServiceModel{S, <:AbstractServiceFormulation}, - incompatible_device_types::Set{<:DataType}, - sys::PSY.System, -) where {S <: PSY.Service} - service = PSY.get_component(S, sys, get_service_name(model)) - if service === nothing - @info "The data doesn't include services of type $(S) and name $(get_service_name(model)), consider changing the service models" _group = - LOG_GROUP_MODELS_VALIDATION - return false - end - - PSY.check_components(sys, service) - services_mapping = PSY.get_contributing_device_mapping(sys) - - contributing_devices_ = - services_mapping[(type = S, name = PSY.get_name(service))].contributing_devices - contributing_devices = [ - d for d in contributing_devices_ if - typeof(d) ∉ incompatible_device_types && PSY.get_available(d) - ] - if isempty(contributing_devices) - @warn "The contributing devices for service $(PSY.get_name(service)) is empty, consider removing the service from the system" _group = - LOG_GROUP_MODELS_VALIDATION - return false - end - - PSY.check_components(sys, contributing_devices) - return true -end - -function validate_services!( - model::ServiceModel{S, <:AbstractServiceFormulation}, - ::Vector{<:DataType}, - sys::PSY.System, -) where {S <: PSY.StaticReserveGroup} - service = PSY.get_component(S, sys, get_service_name(model)) - if service === nothing - @info "The data doesn't include services of type $(S) and name $(get_service_name(model)), consider changing the service models" _group = - LOG_GROUP_MODELS_VALIDATION - return false - end - - PSY.check_components(sys, service) - contributing_services = PSY.get_contributing_services(s) - if isempty(contributing_services) - @warn "The contributing services for group service $(PSY.get_name(service)) is empty, consider removing the group service from the system" _group = - LOG_GROUP_MODELS_VALIDATION - return false - end - - PSY.check_components(sys, contributing_devices) - return true -end From 173840c134a506bea0c3bf70abc13b1aaa2fa9d1 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:56:52 -0600 Subject: [PATCH 030/370] update constructors --- src/services_models/services_constructor.jl | 46 ++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index ecd2a46453..a943ced264 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -30,7 +30,6 @@ function construct_services!( continue end isempty(get_contributing_devices(service_model)) && continue - get_contributing_devices(service_model) construct_service!( container, sys, @@ -463,3 +462,48 @@ function construct_service!( add_constraint_dual!(container, sys, model) return end + +function construct_service!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::ServiceModel{SR, ConstantMaxInterfaceFlow}, + devices_template::Dict{Symbol, DeviceModel}, + incompatible_device_types::Set{<:DataType}, +) where {SR <: PSY.TransmissionInterface} + add_to_expression!( + container, + InterfaceTotalFlow, + FlowActivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_arguments!(container, model, service) + return +end + +function construct_service!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::ServiceModel{SR, ConstantMaxInterfaceFlow}, + devices_template::Dict{Symbol, DeviceModel}, + incompatible_device_types::Set{<:DataType}, +) where {SR <: PSY.TransmissionInterface} + @error("here2") + error() + name = get_service_name(model) + service = PSY.get_component(SR, sys, name) + contributing_devices = get_contributing_devices(model) + + add_constraints!(container, RequirementConstraint, service, contributing_devices, model) + + objective_function!(container, service, model) + + add_feedforward_constraints!(container, model, service) + + add_constraint_dual!(container, sys, model) + + return +end From 6f90f93aebeb8863e37070d5529a5406897ec6f8 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:57:10 -0600 Subject: [PATCH 031/370] wip: add interface code --- src/services_models/transmission_interface.jl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/services_models/transmission_interface.jl diff --git a/src/services_models/transmission_interface.jl b/src/services_models/transmission_interface.jl new file mode 100644 index 0000000000..a8c6edb350 --- /dev/null +++ b/src/services_models/transmission_interface.jl @@ -0,0 +1,19 @@ +function get_default_time_series_names( + ::Type{PSY.TransmissionInterface}, + ::Type{ConstantMaxInterfaceFlow}, +) + return Dict{Type{<:TimeSeriesParameter}, String}() +end + +function get_default_attributes( + ::Type{<:PSY.TransmissionInterface}, + ::Type{ConstantMaxInterfaceFlow}) + return Dict{String, Any}() +end + +function get_initial_conditions_service_model( + ::OperationModel, + ::ServiceModel{T, D}, +) where {T <: PSY.TransmissionInterface, D <: ConstantMaxInterfaceFlow} + return ServiceModel(T, D) +end From 144365aefacfcf8918fb497ebf35021546fd9671 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:57:33 -0600 Subject: [PATCH 032/370] use abstracr service --- src/devices_models/devices/common/add_variable.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/devices/common/add_variable.jl b/src/devices_models/devices/common/add_variable.jl index 6ea4ecdcf1..c9bb403fe3 100644 --- a/src/devices_models/devices/common/add_variable.jl +++ b/src/devices_models/devices/common/add_variable.jl @@ -107,7 +107,7 @@ function add_service_variable!( variable_type::T, service::U, contributing_devices::V, - formulation::AbstractReservesFormulation, + formulation::AbstractServiceFormulation, ) where { T <: VariableType, U <: PSY.Service, From 674d5b00e6a970ed63a2364ef9738cf866295d9b Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:57:49 -0600 Subject: [PATCH 033/370] use deepcopy to avoid issues with templace --- src/operation/decision_model.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index 8222106b1d..7bf2365df6 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -74,10 +74,11 @@ mutable struct DecisionModel{M <: DecisionProblem} <: OperationModel internal = ModelInternal( OptimizationContainer(sys, settings, jump_model, PSY.Deterministic), ) - finalize_template!(template, sys) + template_ = deepcopy(template) + finalize_template!(template_, sys) return new{M}( name, - template, + template_, sys, internal, DecisionModelStore(), From 7fa5a0a1c70a0235626d7e8c5fc4c81363866101 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:58:13 -0600 Subject: [PATCH 034/370] update servies model code --- src/operation/problem_template.jl | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/operation/problem_template.jl b/src/operation/problem_template.jl index 5e39f69525..9042cf03a1 100644 --- a/src/operation/problem_template.jl +++ b/src/operation/problem_template.jl @@ -183,7 +183,9 @@ function _populate_contributing_devices!(template::ProblemTemplate, sys::PSY.Sys isempty(service_models) && return device_models = get_device_models(template) + branch_models = get_branch_models(template) modeled_devices = Set(get_component_type(m) for m in values(device_models)) + union!(modeled_devices, Set(get_component_type(m) for m in values(branch_models))) incompatible_device_types = get_incompatible_devices(device_models) services_mapping = PSY.get_contributing_device_mapping(sys) for (service_key, service_model) in service_models @@ -198,7 +200,6 @@ function _populate_contributing_devices!(template::ProblemTemplate, sys::PSY.Sys end contributing_devices_ = services_mapping[(type = S, name = PSY.get_name(service))].contributing_devices - for d in contributing_devices_ _add_contributing_device_by_type!( service_model, @@ -234,9 +235,17 @@ function _modify_device_model!( end function _modify_device_model!( - devices_template::Dict{Symbol, DeviceModel}, - service_model::ServiceModel{<:PSY.ReserveNonSpinning, <:AbstractReservesFormulation}, - contributing_devices::Vector{<:PSY.Component}, + ::Dict{Symbol, DeviceModel}, + ::ServiceModel{<:PSY.ReserveNonSpinning, <:AbstractReservesFormulation}, + ::Vector{<:PSY.Component}, +) + return +end + +function _modify_device_model!( + ::Dict{Symbol, DeviceModel}, + ::ServiceModel{PSY.TransmissionInterface, ConstantMaxInterfaceFlow}, + ::Vector ) return end From 984b659e83715d42a579d282fc7f8908314782c8 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 00:23:34 -0600 Subject: [PATCH 035/370] minor fix to slacks --- src/services_models/service_slacks.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services_models/service_slacks.jl b/src/services_models/service_slacks.jl index 12835d8d6f..1c6adafa35 100644 --- a/src/services_models/service_slacks.jl +++ b/src/services_models/service_slacks.jl @@ -13,7 +13,7 @@ function reserve_slacks( for t in time_steps variable[t] = JuMP.@variable( - container.JuMPmodel, + get_jump_model(container), base_name = "slack_{$(PSY.get_name(service)), $(t)}", lower_bound = 0.0 ) From b1a63023b91ae10ddc32a5ba3db9ca6b717b1e35 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 00:23:51 -0600 Subject: [PATCH 036/370] more expression updates --- .../devices/common/add_to_expression.jl | 22 +++++++++++++++++++ src/services_models/services_constructor.jl | 4 ++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index ba24c91f15..a892466a48 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -753,6 +753,28 @@ function add_to_expression!( return end +function add_to_expression!( + container::OptimizationContainer, + ::Type{InterfaceTotalFlow}, + ::Type{FlowActivePowerVariable}, + devices::Vector{T}, + model::ServiceModel{PSY.TransmissionInterface, ConstantMaxInterfaceFlow} +) where {T <: PSY.Component} + services = get_available_components(TransmissionInterface, sys) + if !has_container_key(container, InterfaceTotalFlow, TransmissionInterface) + add_expressions!(container, InterfaceTotalFlow, services, model) + end + variable = get_variable(container, FlowActivePowerVariable(), X, service_name) + + expression = get_expression(container, T(), V) + for d in devices, t in get_time_steps(container) + name = PSY.get_name(d) + _add_to_jump_expression!(expression[name, t], variable[name, t], 1.0) + end + return +end + + function add_to_expression!( container::OptimizationContainer, ::Type{T}, diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index a943ced264..818c1ae52e 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -471,13 +471,13 @@ function construct_service!( devices_template::Dict{Symbol, DeviceModel}, incompatible_device_types::Set{<:DataType}, ) where {SR <: PSY.TransmissionInterface} + contributing_devices = get_contributing_devices(model) add_to_expression!( container, InterfaceTotalFlow, FlowActivePowerVariable, - devices, + contributing_devices, model, - network_model, ) add_feedforward_arguments!(container, model, service) return From 29e775a3c1f1229898f151dae15e324a04e69e82 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 17:23:27 -0600 Subject: [PATCH 037/370] add interface flow constraint --- src/core/constraints.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/constraints.jl b/src/core/constraints.jl index 79da9e177c..7e0af2ef48 100644 --- a/src/core/constraints.jl +++ b/src/core/constraints.jl @@ -89,6 +89,7 @@ struct StartupTimeLimitTemperatureConstraint <: ConstraintType end struct PhaseAngleControlLimit <: ConstraintType end struct HVDCLossesAbsoluteValue <: ConstraintType end struct HVDCDirection <: ConstraintType end +struct InterfaceFlowLimit <: ConstraintType end abstract type PowerVariableLimitsConstraint <: ConstraintType end struct InputActivePowerVariableLimitsConstraint <: PowerVariableLimitsConstraint end From 01eb7fc8d81f1e0d3345dc14035efb0c47001965 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 17:23:45 -0600 Subject: [PATCH 038/370] remove duplicate abstraction --- src/core/formulations.jl | 13 +++++++++++-- src/core/service_model.jl | 12 ------------ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 5b09ff9405..de06c6be16 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -233,14 +233,23 @@ import PowerModels: QCRMPowerModel import PowerModels: QCLSPowerModel +""" +Abstract type for Service Formulations (a.k.a Models) + +# Example + +import PowerSimulations +const PSI = PowerSimulations +struct MyServiceFormulation <: PSI.AbstractServiceFormulation +""" abstract type AbstractServiceFormulation end +abstract type AbstractReservesFormulation <: AbstractServiceFormulation end + abstract type AbstractAGCFormulation <: AbstractServiceFormulation end struct PIDSmoothACE <: AbstractAGCFormulation end -abstract type AbstractReservesFormulation <: AbstractServiceFormulation end - struct GroupReserve <: AbstractReservesFormulation end struct RangeReserve <: AbstractReservesFormulation end struct StepwiseCostReserve <: AbstractReservesFormulation end diff --git a/src/core/service_model.jl b/src/core/service_model.jl index 08ed0c701b..6ea786fa81 100644 --- a/src/core/service_model.jl +++ b/src/core/service_model.jl @@ -1,15 +1,3 @@ -""" -Abstract type for Service Formulations (a.k.a Models) - -# Example - -import PowerSimulations -const PSI = PowerSimulations -struct MyServiceFormulation <: PSI.AbstractServiceFormulation -""" -abstract type AbstractServiceFormulation end -abstract type AbstractReservesFormulation <: AbstractServiceFormulation end - function _check_service_formulation( ::Type{D}, ) where {D <: Union{AbstractServiceFormulation, PSY.Service}} From 1515290861572c679da950f4597e44885700ec98 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 18:39:50 -0600 Subject: [PATCH 039/370] fix problem population --- src/operation/problem_template.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/operation/problem_template.jl b/src/operation/problem_template.jl index 9042cf03a1..92e86e8fc5 100644 --- a/src/operation/problem_template.jl +++ b/src/operation/problem_template.jl @@ -245,7 +245,7 @@ end function _modify_device_model!( ::Dict{Symbol, DeviceModel}, ::ServiceModel{PSY.TransmissionInterface, ConstantMaxInterfaceFlow}, - ::Vector + ::Vector, ) return end @@ -269,7 +269,7 @@ function _populate_aggregated_service_model!(template::ProblemTemplate, sys::PSY attributes = get_attributes(service_model) use_slacks = service_model.use_slacks duals = service_model.duals - if get(attributes, "aggregated_service_model", false) + if pop!(attributes, "aggregated_service_model", false) delete!(services_template, key) D = get_component_type(service_model) B = get_formulation(service_model) @@ -284,6 +284,7 @@ function _populate_aggregated_service_model!(template::ProblemTemplate, sys::PSY PSY.get_name(service); use_slacks = use_slacks, duals = duals, + attributes = attributes, ), ) end From ce38a9100a4b7f52378ec3b0dc1f1f5afee940de Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 18:40:05 -0600 Subject: [PATCH 040/370] use reserves abstraction in reserves --- src/services_models/reserves.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/services_models/reserves.jl b/src/services_models/reserves.jl index 33988203cc..f02c13f619 100644 --- a/src/services_models/reserves.jl +++ b/src/services_models/reserves.jl @@ -66,7 +66,10 @@ function get_default_time_series_names( return Dict{Type{<:TimeSeriesParameter}, String}() end -function get_default_attributes(::Type{<:PSY.Reserve}, ::Type{<:AbstractReservesFormulation}) +function get_default_attributes( + ::Type{<:PSY.Reserve}, + ::Type{<:AbstractReservesFormulation}, +) return Dict{String, Any}() end From ff425d98008be480bae0c24a39c4d925c676de12 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 18:44:25 -0600 Subject: [PATCH 041/370] add constructor methods for interfaces --- src/services_models/services_constructor.jl | 44 ++++++++++----------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index 818c1ae52e..fd478750fc 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -66,7 +66,7 @@ function construct_services!( groupservice = key continue end - isempty(get_contributing_devices(service_model)) && continue + isempty(get_contributing_devices_map(service_model)) && continue construct_service!( container, sys, @@ -467,19 +467,20 @@ function construct_service!( container::OptimizationContainer, sys::PSY.System, ::ArgumentConstructStage, - model::ServiceModel{SR, ConstantMaxInterfaceFlow}, + model::ServiceModel{T, ConstantMaxInterfaceFlow}, devices_template::Dict{Symbol, DeviceModel}, incompatible_device_types::Set{<:DataType}, -) where {SR <: PSY.TransmissionInterface} - contributing_devices = get_contributing_devices(model) - add_to_expression!( +) where {T <: PSY.TransmissionInterface} + # contributing_devices_map = get_contributing_devices_map(model) + interfaces = PSY.get_name.(get_available_components(T, sys)) + lazy_container_addition!( container, - InterfaceTotalFlow, - FlowActivePowerVariable, - contributing_devices, - model, + InterfaceTotalFlow(), + T, + interfaces, + get_time_steps(container), ) - add_feedforward_arguments!(container, model, service) + #add_feedforward_arguments!(container, model, service) return end @@ -487,23 +488,22 @@ function construct_service!( container::OptimizationContainer, sys::PSY.System, ::ModelConstructStage, - model::ServiceModel{SR, ConstantMaxInterfaceFlow}, + model::ServiceModel{T, ConstantMaxInterfaceFlow}, devices_template::Dict{Symbol, DeviceModel}, incompatible_device_types::Set{<:DataType}, -) where {SR <: PSY.TransmissionInterface} - @error("here2") - error() +) where {T <: PSY.TransmissionInterface} name = get_service_name(model) - service = PSY.get_component(SR, sys, name) - contributing_devices = get_contributing_devices(model) - - add_constraints!(container, RequirementConstraint, service, contributing_devices, model) - - objective_function!(container, service, model) + service = PSY.get_component(T, sys, name) + add_to_expression!( + container, + InterfaceTotalFlow, + FlowActivePowerVariable, + service, + model, + ) + add_constraints!(container, InterfaceFlowLimit, service, model) add_feedforward_constraints!(container, model, service) - add_constraint_dual!(container, sys, model) - return end From 27b886875fdc5713906136f6fcf3031e0391d358 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 18:44:37 -0600 Subject: [PATCH 042/370] add methods for interface --- .../devices/common/add_to_expression.jl | 32 +++++++++++-------- src/feedforward/feedforward_constraints.jl | 15 ++++++++- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index a892466a48..3b61b16f47 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -757,24 +757,28 @@ function add_to_expression!( container::OptimizationContainer, ::Type{InterfaceTotalFlow}, ::Type{FlowActivePowerVariable}, - devices::Vector{T}, - model::ServiceModel{PSY.TransmissionInterface, ConstantMaxInterfaceFlow} -) where {T <: PSY.Component} - services = get_available_components(TransmissionInterface, sys) - if !has_container_key(container, InterfaceTotalFlow, TransmissionInterface) - add_expressions!(container, InterfaceTotalFlow, services, model) - end - variable = get_variable(container, FlowActivePowerVariable(), X, service_name) - - expression = get_expression(container, T(), V) - for d in devices, t in get_time_steps(container) - name = PSY.get_name(d) - _add_to_jump_expression!(expression[name, t], variable[name, t], 1.0) + service::PSY.TransmissionInterface, + model::ServiceModel{PSY.TransmissionInterface, ConstantMaxInterfaceFlow}, +) + expression = get_expression(container, InterfaceTotalFlow(), PSY.TransmissionInterface) + service_name = get_service_name(model) + for (device_type, devices) in get_contributing_devices_map(model) + variable = get_variable(container, FlowActivePowerVariable(), device_type) + for d in devices + name = PSY.get_name(d) + direction = get(PSY.get_direction_mapping(service), name, 1.0) + for t in get_time_steps(container) + _add_to_jump_expression!( + expression[service_name, t], + variable[name, t], + direction, + ) + end + end end return end - function add_to_expression!( container::OptimizationContainer, ::Type{T}, diff --git a/src/feedforward/feedforward_constraints.jl b/src/feedforward/feedforward_constraints.jl index 200f9988da..ee676f288d 100644 --- a/src/feedforward/feedforward_constraints.jl +++ b/src/feedforward/feedforward_constraints.jl @@ -12,7 +12,7 @@ end function add_feedforward_constraints!( container::OptimizationContainer, - model::ServiceModel, + model::ServiceModel{V, <:AbstractReservesFormulation}, ::V, ) where {V <: PSY.AbstractReserve} for ff in get_feedforwards(model) @@ -23,6 +23,19 @@ function add_feedforward_constraints!( return end +function add_feedforward_constraints!( + container::OptimizationContainer, + model::ServiceModel, + ::V, +) where {V <: PSY.Service} + for ff in get_feedforwards(model) + @debug "constraints" ff V _group = LOG_GROUP_FEEDFORWARDS_CONSTRUCTION + contributing_devices = get_contributing_devices(model) + add_feedforward_constraints!(container, model, contributing_devices, ff) + end + return +end + function _add_feedforward_constraints!( container::OptimizationContainer, ::Type{T}, From 515f663d3fe3c0a06bc6092632c151e5659f6f59 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 18:44:47 -0600 Subject: [PATCH 043/370] implement interface constraints --- src/services_models/transmission_interface.jl | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/services_models/transmission_interface.jl b/src/services_models/transmission_interface.jl index a8c6edb350..add9e99104 100644 --- a/src/services_models/transmission_interface.jl +++ b/src/services_models/transmission_interface.jl @@ -17,3 +17,37 @@ function get_initial_conditions_service_model( ) where {T <: PSY.TransmissionInterface, D <: ConstantMaxInterfaceFlow} return ServiceModel(T, D) end + +function add_constraints!(container::OptimizationContainer, + ::Type{InterfaceFlowLimit}, + interface::T, + model::ServiceModel{T, ConstantMaxInterfaceFlow}, +) where {T <: PSY.TransmissionInterface} + expr = get_expression(container, InterfaceTotalFlow(), T) + interfaces, timesteps = axes(expr) + constraint_container_ub = lazy_container_addition!( + container, + InterfaceFlowLimit(), + T, + interfaces, + timesteps; + meta = "ub", + ) + constraint_container_lb = lazy_container_addition!( + container, + InterfaceFlowLimit(), + T, + interfaces, + timesteps; + meta = "lb", + ) + int_name = PSY.get_name(interface) + min_flow, max_flow = PSY.get_active_power_flow_limits(interface) + for t in timesteps + constraint_container_ub[int_name, t] = + JuMP.@constraint(get_jump_model(container), expr[int_name, t] <= max_flow) + constraint_container_lb[int_name, t] = + JuMP.@constraint(get_jump_model(container), expr[int_name, t] >= min_flow) + end + return +end From d08eb560a5920576442c2b2544395a703c346bca Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 23 May 2023 18:32:24 -0700 Subject: [PATCH 044/370] add scripts --- scripts/create_rts_systems.jl | 2 ++ scripts/rts_simulation_setup.jl | 21 ++++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/scripts/create_rts_systems.jl b/scripts/create_rts_systems.jl index ae4d33d819..3466df006f 100644 --- a/scripts/create_rts_systems.jl +++ b/scripts/create_rts_systems.jl @@ -178,6 +178,7 @@ for sys in [sys_DA, sys_RT, sys_RT_HourAhead] end =# + #= for g in get_components(HydroEnergyReservoir, sys) area_name = get_name(get_area(get_bus(g))) reg_up = get_component(VariableReserve, sys, area_maps_regup[area_name]) @@ -187,6 +188,7 @@ for sys in [sys_DA, sys_RT, sys_RT_HourAhead] add_service!(g, reg_dn, sys) add_service!(g, reg_spin, sys) end + =# #Remove units that make no sense to include names = [ diff --git a/scripts/rts_simulation_setup.jl b/scripts/rts_simulation_setup.jl index c56efda8c7..8a1075d81b 100644 --- a/scripts/rts_simulation_setup.jl +++ b/scripts/rts_simulation_setup.jl @@ -15,6 +15,7 @@ using JuMP using Logging using Dates using TimeSeries +using PlotlyJS include("script_utils.jl") @@ -22,7 +23,7 @@ sys_DA = System("data/sys_DA_1h.json") sys_RT = System("data/sys_RT_5min.json") mipgap = 1e-2 # 1% -num_steps = 30 +num_steps = 2 starttime = DateTime("2020-01-01T00:00:00") template_uc = get_uc_ptdf_template(sys_DA) @@ -98,6 +99,22 @@ sim = Simulation(; build!(sim; console_level = Logging.Info, serialize = false) execute!(sim; enable_progress_bar = true); +results_nrb = SimulationResults(sim; ignore_status = true) +results_uc_nrb = get_decision_problem_results(results_nrb, "UC") +results_ed_nrb = get_decision_problem_results(results_nrb, "ED") + +regup_uc = read_realized_variable(results_uc_nrb, "ActivePowerReserveVariable__VariableReserve__ReserveUp__Reg_Up_R1") +dates_uc = regup_uc[!, "DateTime"] +regup_uc_st4 = regup_uc[!, "123_STEAM_2"] + +regup_ed = read_realized_parameter(results_ed_nrb, "FixValueParameter__VariableReserve__ReserveUp__Reg_Up_R1") +dates_ed = regup_ed[!, "DateTime"] +regup_ed_st4 = regup_ed[!, "123_STEAM_2"] +regup_ed_var = read_realized_variable(results_ed_nrb, "ActivePowerReserveVariable__VariableReserve__ReserveUp__Reg_Up_R1") +regup_ed_var_st4 = regup_ed_var[!, "123_STEAM_2"] + +PlotlyJS.plot([PlotlyJS.scatter(x = dates_uc, y = regup_uc_st4 , name = "UC", line_shape = "hv"), PlotlyJS.scatter(x= dates_ed, y = regup_ed_st4 .* 100.0, name = "ED", line_shape = "hv"), PlotlyJS.scatter(x= dates_ed, y = regup_ed_var_st4, name = "ED Var", line_shape = "hv")]) + uc = sim.models.decision_models[1] ed = sim.models.decision_models[2] vars = ed.internal.container.variables @@ -153,3 +170,5 @@ C1598 column UP .000000 C10643 column LO 1.000000 C11317 column LO 1.000000 =# + +# ActivePowerVariable_ThermalStandard_{322_CT_6, 1} - 0.55 _[1465] + ActivePowerReserveVariable_VariableReserve{ReserveUp}_Reg_Up_R3_{322_CT_6, 1} - x[322_CT_6,1] ≤ 0.0 \ No newline at end of file From 6b564f8353cbf7ee4fcb7537fe1158797c7e1984 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 23 May 2023 18:33:05 -0700 Subject: [PATCH 045/370] Fix service models feedforwards Co-authored-by: jdlara --- src/parameters/add_parameters.jl | 40 +++++++++++++++++++++++++++++ src/parameters/update_parameters.jl | 1 + src/services_models/reserves.jl | 2 +- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index 0c03ce4547..aa1a3df0fa 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -34,6 +34,7 @@ function add_parameters!( return end +#= function add_parameters!( container::OptimizationContainer, ::Type{T}, @@ -53,6 +54,7 @@ function add_parameters!( _add_parameters!(container, T(), source_key, model, devices) return end +=# function add_parameters!( container::OptimizationContainer, @@ -107,6 +109,27 @@ function add_parameters!( return end +function add_parameters!( + container::OptimizationContainer, + ::Type{T}, + ff::FixValueFeedforward, + model::ServiceModel{K, W}, + devices::V, +) where { + T <: VariableValueParameter, + V <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, + W <: AbstractServiceFormulation, + K <: PSY.Reserve, +} where {D <: PSY.Component} + if get_rebuild_model(get_settings(container)) && has_container_key(container, T, D) + return + end + source_key = get_optimization_container_key(ff) + _add_parameters!(container, T(), source_key, model, devices) + _set_affected_variables!(container, T(), K, ff) + return +end + function _set_affected_variables!( container::OptimizationContainer, ::T, @@ -125,6 +148,23 @@ function _set_affected_variables!( return end +function _set_affected_variables!( + container::OptimizationContainer, + ::T, + device_type::Type{U}, + ff::FixValueFeedforward, +) where { + T <: VariableValueParameter, + U <: PSY.Service, +} + meta = ff.optimization_container_key.meta + parameter_container = get_parameter(container, T(), U, meta) + param_attributes = get_attributes(parameter_container) + affected_variables = get_affected_values(ff) + push!(param_attributes.affected_keys, affected_variables...) + return +end + function _add_parameters!( container::OptimizationContainer, param::T, diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index 6a01c8b4e7..65ee0183c5 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -531,6 +531,7 @@ function _fix_parameter_value!( parameter_attributes::VariableValueAttributes, ) affected_variable_keys = parameter_attributes.affected_keys + @assert !isempty(affected_variable_keys) for var_key in affected_variable_keys variable = get_variable(container, var_key) component_names, time = axes(parameter_array) diff --git a/src/services_models/reserves.jl b/src/services_models/reserves.jl index cbc1251d3f..9351b32244 100644 --- a/src/services_models/reserves.jl +++ b/src/services_models/reserves.jl @@ -27,7 +27,7 @@ get_multiplier_value(::RequirementTimeSeriesParameter, d::PSY.Reserve, ::Abstrac get_multiplier_value(::RequirementTimeSeriesParameter, d::PSY.ReserveNonSpinning, ::AbstractReservesFormulation) = PSY.get_requirement(d) get_parameter_multiplier(::VariableValueParameter, d::Type{<:PSY.AbstractReserve}, ::AbstractReservesFormulation) = 1.0 -get_initial_parameter_value(::VariableValueParameter, d::Type{<:PSY.AbstractReserve}, ::AbstractReservesFormulation) = 1.0 +get_initial_parameter_value(::VariableValueParameter, d::Type{<:PSY.AbstractReserve}, ::AbstractReservesFormulation) = 0.0 objective_function_multiplier(::ServiceRequirementVariable, ::StepwiseCostReserve) = 1.0 sos_status(::PSY.ReserveDemandCurve, ::StepwiseCostReserve)=SOSStatusVariable.NO_VARIABLE From 01f60b68e3cd1012265aab9b7b5ffb62998381b1 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 24 May 2023 13:09:21 -0600 Subject: [PATCH 046/370] update deps --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index b65bf62e24..967ce8b0b6 100644 --- a/Project.toml +++ b/Project.toml @@ -43,7 +43,7 @@ JuMP = "1" MathOptInterface = "1" PowerModels = "~0.19" PowerNetworkMatrices = "^0.7" -PowerSystems = "2" +PowerSystems = "^2.3" PrettyTables = "^1.3, 2" ProgressMeter = "^1.5" TimeSeries = "~0.23" From 2a52d0927046b7f48877925a0775798e36665a4c Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 24 May 2023 16:24:03 -0700 Subject: [PATCH 047/370] formatter --- scripts/rts_simulation_setup.jl | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/scripts/rts_simulation_setup.jl b/scripts/rts_simulation_setup.jl index 8a1075d81b..bc71853963 100644 --- a/scripts/rts_simulation_setup.jl +++ b/scripts/rts_simulation_setup.jl @@ -103,17 +103,40 @@ results_nrb = SimulationResults(sim; ignore_status = true) results_uc_nrb = get_decision_problem_results(results_nrb, "UC") results_ed_nrb = get_decision_problem_results(results_nrb, "ED") -regup_uc = read_realized_variable(results_uc_nrb, "ActivePowerReserveVariable__VariableReserve__ReserveUp__Reg_Up_R1") +regup_uc = read_realized_variable( + results_uc_nrb, + "ActivePowerReserveVariable__VariableReserve__ReserveUp__Reg_Up_R1", +) dates_uc = regup_uc[!, "DateTime"] regup_uc_st4 = regup_uc[!, "123_STEAM_2"] -regup_ed = read_realized_parameter(results_ed_nrb, "FixValueParameter__VariableReserve__ReserveUp__Reg_Up_R1") +regup_ed = read_realized_parameter( + results_ed_nrb, + "FixValueParameter__VariableReserve__ReserveUp__Reg_Up_R1", +) dates_ed = regup_ed[!, "DateTime"] regup_ed_st4 = regup_ed[!, "123_STEAM_2"] -regup_ed_var = read_realized_variable(results_ed_nrb, "ActivePowerReserveVariable__VariableReserve__ReserveUp__Reg_Up_R1") +regup_ed_var = read_realized_variable( + results_ed_nrb, + "ActivePowerReserveVariable__VariableReserve__ReserveUp__Reg_Up_R1", +) regup_ed_var_st4 = regup_ed_var[!, "123_STEAM_2"] -PlotlyJS.plot([PlotlyJS.scatter(x = dates_uc, y = regup_uc_st4 , name = "UC", line_shape = "hv"), PlotlyJS.scatter(x= dates_ed, y = regup_ed_st4 .* 100.0, name = "ED", line_shape = "hv"), PlotlyJS.scatter(x= dates_ed, y = regup_ed_var_st4, name = "ED Var", line_shape = "hv")]) +PlotlyJS.plot([ + PlotlyJS.scatter(; x = dates_uc, y = regup_uc_st4, name = "UC", line_shape = "hv"), + PlotlyJS.scatter(; + x = dates_ed, + y = regup_ed_st4 .* 100.0, + name = "ED", + line_shape = "hv", + ), + PlotlyJS.scatter(; + x = dates_ed, + y = regup_ed_var_st4, + name = "ED Var", + line_shape = "hv", + ), +]) uc = sim.models.decision_models[1] ed = sim.models.decision_models[2] @@ -171,4 +194,4 @@ C10643 column LO 1.000000 C11317 column LO 1.000000 =# -# ActivePowerVariable_ThermalStandard_{322_CT_6, 1} - 0.55 _[1465] + ActivePowerReserveVariable_VariableReserve{ReserveUp}_Reg_Up_R3_{322_CT_6, 1} - x[322_CT_6,1] ≤ 0.0 \ No newline at end of file +# ActivePowerVariable_ThermalStandard_{322_CT_6, 1} - 0.55 _[1465] + ActivePowerReserveVariable_VariableReserve{ReserveUp}_Reg_Up_R3_{322_CT_6, 1} - x[322_CT_6,1] ≤ 0.0 From 272400fe38bf691dbd58d627f0598da6dcb078ec Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 14 Jun 2023 12:12:20 -0600 Subject: [PATCH 048/370] fix group reserves --- src/PowerSimulations.jl | 1 + src/services_models/agc.jl | 14 ++++++++++++++ src/services_models/reserve_group.jl | 11 +++++++++++ src/services_models/reserves.jl | 18 ++++++++++++++++-- test/test_basic_model_structs.jl | 4 ++-- 5 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 src/services_models/reserve_group.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 5155090bf9..4b8e7a643f 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -541,6 +541,7 @@ include("devices_models/devices/regulation_device.jl") # Services Models include("services_models/agc.jl") include("services_models/reserves.jl") +include("services_models/reserve_group.jl") include("services_models/transmission_interface.jl") include("services_models/group_reserve.jl") include("services_models/service_slacks.jl") diff --git a/src/services_models/agc.jl b/src/services_models/agc.jl index 3de0ddffdf..3ad04e7799 100644 --- a/src/services_models/agc.jl +++ b/src/services_models/agc.jl @@ -45,6 +45,20 @@ get_variable_multiplier(::SteadyStateFrequencyDeviation, d::PSY.AGC, ::AbstractA #! format: on +function get_default_time_series_names( + ::Type{PSY.AGC}, + ::Type{<:AbstractAGCFormulation}, +) + return Dict{Type{<:TimeSeriesParameter}, String}() +end + +function get_default_attributes( + ::Type{PSY.AGC}, + ::Type{<:AbstractAGCFormulation}, +) + return Dict{String, Any}() +end + """ Steady State deviation of the frequency """ diff --git a/src/services_models/reserve_group.jl b/src/services_models/reserve_group.jl new file mode 100644 index 0000000000..b64e1613a7 --- /dev/null +++ b/src/services_models/reserve_group.jl @@ -0,0 +1,11 @@ +function get_default_time_series_names( + ::Type{PSY.StaticReserveGroup{T}}, + ::Type{GroupReserve}) where {T <: PSY.ReserveDirection} + return Dict{String, Any}() +end + +function get_default_attributes( + ::Type{PSY.StaticReserveGroup{T}}, + ::Type{GroupReserve}) where {T <: PSY.ReserveDirection} + return Dict{String, Any}() +end diff --git a/src/services_models/reserves.jl b/src/services_models/reserves.jl index f02c13f619..f97ed1f2a1 100644 --- a/src/services_models/reserves.jl +++ b/src/services_models/reserves.jl @@ -41,6 +41,13 @@ function get_initial_conditions_service_model( return ServiceModel(T, D) end +function get_initial_conditions_service_model( + ::OperationModel, + ::ServiceModel{T, D}, +) where {T <: PSY.VariableReserveNonSpinning, D <: AbstractReservesFormulation} + return ServiceModel(T, D) +end + function get_default_time_series_names( ::Type{<:PSY.Reserve}, ::Type{T}, @@ -60,9 +67,9 @@ function get_default_time_series_names( end function get_default_time_series_names( - ::Type{<:PSY.Reserve}, + ::Type{T}, ::Type{<:AbstractReservesFormulation}, -) +) where {T <: PSY.Reserve} return Dict{Type{<:TimeSeriesParameter}, String}() end @@ -73,6 +80,13 @@ function get_default_attributes( return Dict{String, Any}() end +function get_default_attributes( + ::Type{<:PSY.ReserveNonSpinning}, + ::Type{<:AbstractReservesFormulation}, +) + return Dict{String, Any}() +end + ################################## Reserve Requirement Constraint ########################## function add_constraints!( container::OptimizationContainer, diff --git a/test/test_basic_model_structs.jl b/test/test_basic_model_structs.jl index 865705f8fa..6928b5e196 100644 --- a/test/test_basic_model_structs.jl +++ b/test/test_basic_model_structs.jl @@ -9,10 +9,10 @@ end end @testset "ServiceModel Tests" begin - @test_throws ArgumentError ServiceModel(AGC, PSI.AbstractServiceFormulation, "TestName") + @test_throws ArgumentError ServiceModel(AGC, PSI.AbstractAGCFormulation, "TestName") @test_throws ArgumentError ServiceModel( VariableReserve{PSY.ReserveUp}, - PSI.AbstractServiceFormulation, + PSI.AbstractReservesFormulation, "TestName2", ) end From 05dae7883d08a78b86040d46a3e0c6ed141a5f12 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 12:25:19 -0600 Subject: [PATCH 049/370] use reserves in reserve models --- src/services_models/reserves.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/services_models/reserves.jl b/src/services_models/reserves.jl index cbc1251d3f..33988203cc 100644 --- a/src/services_models/reserves.jl +++ b/src/services_models/reserves.jl @@ -37,7 +37,7 @@ uses_compact_power(::PSY.ReserveDemandCurve, ::StepwiseCostReserve)=false function get_initial_conditions_service_model( ::OperationModel, ::ServiceModel{T, D}, -) where {T <: PSY.Service, D <: AbstractServiceFormulation} +) where {T <: PSY.Reserve, D <: AbstractReservesFormulation} return ServiceModel(T, D) end @@ -60,13 +60,13 @@ function get_default_time_series_names( end function get_default_time_series_names( - ::Type{<:PSY.Service}, - ::Type{<:AbstractServiceFormulation}, + ::Type{<:PSY.Reserve}, + ::Type{<:AbstractReservesFormulation}, ) return Dict{Type{<:TimeSeriesParameter}, String}() end -function get_default_attributes(::Type{<:PSY.Service}, ::Type{<:AbstractServiceFormulation}) +function get_default_attributes(::Type{<:PSY.Reserve}, ::Type{<:AbstractReservesFormulation}) return Dict{String, Any}() end From 04e21a3ffb0ee26c4c841a72a632eabe58d25086 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 12:25:29 -0600 Subject: [PATCH 050/370] add interface formulations --- src/PowerSimulations.jl | 3 +++ src/core/formulations.jl | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index b1e31398f6..5155090bf9 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -35,6 +35,8 @@ export StepwiseCostReserve export NonSpinningReserve export PIDSmoothACE export GroupReserve +export ConstantMaxInterfaceFlow + ######## Branch Models ######## export StaticBranch export StaticBranchBounds @@ -539,6 +541,7 @@ include("devices_models/devices/regulation_device.jl") # Services Models include("services_models/agc.jl") include("services_models/reserves.jl") +include("services_models/transmission_interface.jl") include("services_models/group_reserve.jl") include("services_models/service_slacks.jl") include("services_models/services_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index dedffc553a..5b09ff9405 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -246,3 +246,5 @@ struct RangeReserve <: AbstractReservesFormulation end struct StepwiseCostReserve <: AbstractReservesFormulation end struct RampReserve <: AbstractReservesFormulation end struct NonSpinningReserve <: AbstractReservesFormulation end + +struct ConstantMaxInterfaceFlow <: AbstractServiceFormulation end From d467f39f07ad6cbebfb4950123787c4ffe0cf1e5 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:55:57 -0600 Subject: [PATCH 051/370] add new expression types --- src/core/expressions.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/expressions.jl b/src/core/expressions.jl index 89c6a8df15..ab981f4f45 100644 --- a/src/core/expressions.jl +++ b/src/core/expressions.jl @@ -47,9 +47,12 @@ struct ReserveRangeExpressionUB <: RangeConstraintUBExpressions end struct ComponentActivePowerRangeExpressionUB <: RangeConstraintUBExpressions end struct ComponentReserveUpBalanceExpression <: ExpressionType end struct ComponentReserveDownBalanceExpression <: ExpressionType end +struct InterfaceTotalFlow <: ExpressionType end should_write_resulting_value(::Type{<:ExpressionType}) = false should_write_resulting_value(::Type{<:CostExpressions}) = true +should_write_resulting_value(::Type{InterfaceTotalFlow}) = true should_write_resulting_value(::Type{RawACE}) = true convert_result_to_natural_units(::Type{<:ExpressionType}) = false +convert_result_to_natural_units(::Type{InterfaceTotalFlow}) = true From 8e126bcd2fcd32f4314e22241cd1748551cd2b53 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:56:05 -0600 Subject: [PATCH 052/370] remove stale code --- .../constructor_validations.jl | 55 ------------------- 1 file changed, 55 deletions(-) diff --git a/src/devices_models/device_constructors/constructor_validations.jl b/src/devices_models/device_constructors/constructor_validations.jl index 50fd4a3bff..dbf142ae00 100644 --- a/src/devices_models/device_constructors/constructor_validations.jl +++ b/src/devices_models/device_constructors/constructor_validations.jl @@ -10,58 +10,3 @@ function validate_available_devices( PSY.check_components(system, devices) return true end - -function validate_service!( - model::ServiceModel{S, <:AbstractServiceFormulation}, - incompatible_device_types::Set{<:DataType}, - sys::PSY.System, -) where {S <: PSY.Service} - service = PSY.get_component(S, sys, get_service_name(model)) - if service === nothing - @info "The data doesn't include services of type $(S) and name $(get_service_name(model)), consider changing the service models" _group = - LOG_GROUP_MODELS_VALIDATION - return false - end - - PSY.check_components(sys, service) - services_mapping = PSY.get_contributing_device_mapping(sys) - - contributing_devices_ = - services_mapping[(type = S, name = PSY.get_name(service))].contributing_devices - contributing_devices = [ - d for d in contributing_devices_ if - typeof(d) ∉ incompatible_device_types && PSY.get_available(d) - ] - if isempty(contributing_devices) - @warn "The contributing devices for service $(PSY.get_name(service)) is empty, consider removing the service from the system" _group = - LOG_GROUP_MODELS_VALIDATION - return false - end - - PSY.check_components(sys, contributing_devices) - return true -end - -function validate_services!( - model::ServiceModel{S, <:AbstractServiceFormulation}, - ::Vector{<:DataType}, - sys::PSY.System, -) where {S <: PSY.StaticReserveGroup} - service = PSY.get_component(S, sys, get_service_name(model)) - if service === nothing - @info "The data doesn't include services of type $(S) and name $(get_service_name(model)), consider changing the service models" _group = - LOG_GROUP_MODELS_VALIDATION - return false - end - - PSY.check_components(sys, service) - contributing_services = PSY.get_contributing_services(s) - if isempty(contributing_services) - @warn "The contributing services for group service $(PSY.get_name(service)) is empty, consider removing the group service from the system" _group = - LOG_GROUP_MODELS_VALIDATION - return false - end - - PSY.check_components(sys, contributing_devices) - return true -end From 0f0b79be2933b86024cf629c121853b0372965fb Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:56:52 -0600 Subject: [PATCH 053/370] update constructors --- src/services_models/services_constructor.jl | 46 ++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index ecd2a46453..a943ced264 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -30,7 +30,6 @@ function construct_services!( continue end isempty(get_contributing_devices(service_model)) && continue - get_contributing_devices(service_model) construct_service!( container, sys, @@ -463,3 +462,48 @@ function construct_service!( add_constraint_dual!(container, sys, model) return end + +function construct_service!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::ServiceModel{SR, ConstantMaxInterfaceFlow}, + devices_template::Dict{Symbol, DeviceModel}, + incompatible_device_types::Set{<:DataType}, +) where {SR <: PSY.TransmissionInterface} + add_to_expression!( + container, + InterfaceTotalFlow, + FlowActivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_arguments!(container, model, service) + return +end + +function construct_service!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::ServiceModel{SR, ConstantMaxInterfaceFlow}, + devices_template::Dict{Symbol, DeviceModel}, + incompatible_device_types::Set{<:DataType}, +) where {SR <: PSY.TransmissionInterface} + @error("here2") + error() + name = get_service_name(model) + service = PSY.get_component(SR, sys, name) + contributing_devices = get_contributing_devices(model) + + add_constraints!(container, RequirementConstraint, service, contributing_devices, model) + + objective_function!(container, service, model) + + add_feedforward_constraints!(container, model, service) + + add_constraint_dual!(container, sys, model) + + return +end From cc1fd4856036cc302ffeada75e345f7f04165bca Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:57:10 -0600 Subject: [PATCH 054/370] wip: add interface code --- src/services_models/transmission_interface.jl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/services_models/transmission_interface.jl diff --git a/src/services_models/transmission_interface.jl b/src/services_models/transmission_interface.jl new file mode 100644 index 0000000000..a8c6edb350 --- /dev/null +++ b/src/services_models/transmission_interface.jl @@ -0,0 +1,19 @@ +function get_default_time_series_names( + ::Type{PSY.TransmissionInterface}, + ::Type{ConstantMaxInterfaceFlow}, +) + return Dict{Type{<:TimeSeriesParameter}, String}() +end + +function get_default_attributes( + ::Type{<:PSY.TransmissionInterface}, + ::Type{ConstantMaxInterfaceFlow}) + return Dict{String, Any}() +end + +function get_initial_conditions_service_model( + ::OperationModel, + ::ServiceModel{T, D}, +) where {T <: PSY.TransmissionInterface, D <: ConstantMaxInterfaceFlow} + return ServiceModel(T, D) +end From 3c4d4686ba8cf7439a68ee1776cc4c71c5c20ddb Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:57:33 -0600 Subject: [PATCH 055/370] use abstracr service --- src/devices_models/devices/common/add_variable.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/devices/common/add_variable.jl b/src/devices_models/devices/common/add_variable.jl index 6ea4ecdcf1..c9bb403fe3 100644 --- a/src/devices_models/devices/common/add_variable.jl +++ b/src/devices_models/devices/common/add_variable.jl @@ -107,7 +107,7 @@ function add_service_variable!( variable_type::T, service::U, contributing_devices::V, - formulation::AbstractReservesFormulation, + formulation::AbstractServiceFormulation, ) where { T <: VariableType, U <: PSY.Service, From 9597eb095301206363b8a4456acefb47f38204ef Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:57:49 -0600 Subject: [PATCH 056/370] use deepcopy to avoid issues with templace --- src/operation/decision_model.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index cd0fa9d1e3..8427b0fa7d 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -74,10 +74,11 @@ mutable struct DecisionModel{M <: DecisionProblem} <: OperationModel internal = ModelInternal( OptimizationContainer(sys, settings, jump_model, PSY.Deterministic), ) - finalize_template!(template, sys) + template_ = deepcopy(template) + finalize_template!(template_, sys) return new{M}( name, - template, + template_, sys, internal, DecisionModelStore(), From e80da894e1081b440520011a9e1b4aff00449741 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:58:13 -0600 Subject: [PATCH 057/370] update servies model code --- src/operation/problem_template.jl | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/operation/problem_template.jl b/src/operation/problem_template.jl index 5e39f69525..9042cf03a1 100644 --- a/src/operation/problem_template.jl +++ b/src/operation/problem_template.jl @@ -183,7 +183,9 @@ function _populate_contributing_devices!(template::ProblemTemplate, sys::PSY.Sys isempty(service_models) && return device_models = get_device_models(template) + branch_models = get_branch_models(template) modeled_devices = Set(get_component_type(m) for m in values(device_models)) + union!(modeled_devices, Set(get_component_type(m) for m in values(branch_models))) incompatible_device_types = get_incompatible_devices(device_models) services_mapping = PSY.get_contributing_device_mapping(sys) for (service_key, service_model) in service_models @@ -198,7 +200,6 @@ function _populate_contributing_devices!(template::ProblemTemplate, sys::PSY.Sys end contributing_devices_ = services_mapping[(type = S, name = PSY.get_name(service))].contributing_devices - for d in contributing_devices_ _add_contributing_device_by_type!( service_model, @@ -234,9 +235,17 @@ function _modify_device_model!( end function _modify_device_model!( - devices_template::Dict{Symbol, DeviceModel}, - service_model::ServiceModel{<:PSY.ReserveNonSpinning, <:AbstractReservesFormulation}, - contributing_devices::Vector{<:PSY.Component}, + ::Dict{Symbol, DeviceModel}, + ::ServiceModel{<:PSY.ReserveNonSpinning, <:AbstractReservesFormulation}, + ::Vector{<:PSY.Component}, +) + return +end + +function _modify_device_model!( + ::Dict{Symbol, DeviceModel}, + ::ServiceModel{PSY.TransmissionInterface, ConstantMaxInterfaceFlow}, + ::Vector ) return end From ad9c13990593923e21ba3c882ad830067ef33046 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 00:23:34 -0600 Subject: [PATCH 058/370] minor fix to slacks --- src/services_models/service_slacks.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services_models/service_slacks.jl b/src/services_models/service_slacks.jl index 12835d8d6f..1c6adafa35 100644 --- a/src/services_models/service_slacks.jl +++ b/src/services_models/service_slacks.jl @@ -13,7 +13,7 @@ function reserve_slacks( for t in time_steps variable[t] = JuMP.@variable( - container.JuMPmodel, + get_jump_model(container), base_name = "slack_{$(PSY.get_name(service)), $(t)}", lower_bound = 0.0 ) From a568e434736da914bd95a146936c277e38b454f6 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 00:23:51 -0600 Subject: [PATCH 059/370] more expression updates --- .../devices/common/add_to_expression.jl | 22 +++++++++++++++++++ src/services_models/services_constructor.jl | 4 ++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index ba24c91f15..a892466a48 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -753,6 +753,28 @@ function add_to_expression!( return end +function add_to_expression!( + container::OptimizationContainer, + ::Type{InterfaceTotalFlow}, + ::Type{FlowActivePowerVariable}, + devices::Vector{T}, + model::ServiceModel{PSY.TransmissionInterface, ConstantMaxInterfaceFlow} +) where {T <: PSY.Component} + services = get_available_components(TransmissionInterface, sys) + if !has_container_key(container, InterfaceTotalFlow, TransmissionInterface) + add_expressions!(container, InterfaceTotalFlow, services, model) + end + variable = get_variable(container, FlowActivePowerVariable(), X, service_name) + + expression = get_expression(container, T(), V) + for d in devices, t in get_time_steps(container) + name = PSY.get_name(d) + _add_to_jump_expression!(expression[name, t], variable[name, t], 1.0) + end + return +end + + function add_to_expression!( container::OptimizationContainer, ::Type{T}, diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index a943ced264..818c1ae52e 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -471,13 +471,13 @@ function construct_service!( devices_template::Dict{Symbol, DeviceModel}, incompatible_device_types::Set{<:DataType}, ) where {SR <: PSY.TransmissionInterface} + contributing_devices = get_contributing_devices(model) add_to_expression!( container, InterfaceTotalFlow, FlowActivePowerVariable, - devices, + contributing_devices, model, - network_model, ) add_feedforward_arguments!(container, model, service) return From 62e2355f843a8e364f1e2870f3341c9782a3d99f Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 17:23:27 -0600 Subject: [PATCH 060/370] add interface flow constraint --- src/core/constraints.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/constraints.jl b/src/core/constraints.jl index 79da9e177c..7e0af2ef48 100644 --- a/src/core/constraints.jl +++ b/src/core/constraints.jl @@ -89,6 +89,7 @@ struct StartupTimeLimitTemperatureConstraint <: ConstraintType end struct PhaseAngleControlLimit <: ConstraintType end struct HVDCLossesAbsoluteValue <: ConstraintType end struct HVDCDirection <: ConstraintType end +struct InterfaceFlowLimit <: ConstraintType end abstract type PowerVariableLimitsConstraint <: ConstraintType end struct InputActivePowerVariableLimitsConstraint <: PowerVariableLimitsConstraint end From 847171b624de80e800dbaf9f6d61b82e0323df0d Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 17:23:45 -0600 Subject: [PATCH 061/370] remove duplicate abstraction --- src/core/formulations.jl | 13 +++++++++++-- src/core/service_model.jl | 12 ------------ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 5b09ff9405..de06c6be16 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -233,14 +233,23 @@ import PowerModels: QCRMPowerModel import PowerModels: QCLSPowerModel +""" +Abstract type for Service Formulations (a.k.a Models) + +# Example + +import PowerSimulations +const PSI = PowerSimulations +struct MyServiceFormulation <: PSI.AbstractServiceFormulation +""" abstract type AbstractServiceFormulation end +abstract type AbstractReservesFormulation <: AbstractServiceFormulation end + abstract type AbstractAGCFormulation <: AbstractServiceFormulation end struct PIDSmoothACE <: AbstractAGCFormulation end -abstract type AbstractReservesFormulation <: AbstractServiceFormulation end - struct GroupReserve <: AbstractReservesFormulation end struct RangeReserve <: AbstractReservesFormulation end struct StepwiseCostReserve <: AbstractReservesFormulation end diff --git a/src/core/service_model.jl b/src/core/service_model.jl index 08ed0c701b..6ea786fa81 100644 --- a/src/core/service_model.jl +++ b/src/core/service_model.jl @@ -1,15 +1,3 @@ -""" -Abstract type for Service Formulations (a.k.a Models) - -# Example - -import PowerSimulations -const PSI = PowerSimulations -struct MyServiceFormulation <: PSI.AbstractServiceFormulation -""" -abstract type AbstractServiceFormulation end -abstract type AbstractReservesFormulation <: AbstractServiceFormulation end - function _check_service_formulation( ::Type{D}, ) where {D <: Union{AbstractServiceFormulation, PSY.Service}} From 5cd3dbad2f6ecc0c3b4ce7ae521388d0d2d03701 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 18:39:50 -0600 Subject: [PATCH 062/370] fix problem population --- src/operation/problem_template.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/operation/problem_template.jl b/src/operation/problem_template.jl index 9042cf03a1..92e86e8fc5 100644 --- a/src/operation/problem_template.jl +++ b/src/operation/problem_template.jl @@ -245,7 +245,7 @@ end function _modify_device_model!( ::Dict{Symbol, DeviceModel}, ::ServiceModel{PSY.TransmissionInterface, ConstantMaxInterfaceFlow}, - ::Vector + ::Vector, ) return end @@ -269,7 +269,7 @@ function _populate_aggregated_service_model!(template::ProblemTemplate, sys::PSY attributes = get_attributes(service_model) use_slacks = service_model.use_slacks duals = service_model.duals - if get(attributes, "aggregated_service_model", false) + if pop!(attributes, "aggregated_service_model", false) delete!(services_template, key) D = get_component_type(service_model) B = get_formulation(service_model) @@ -284,6 +284,7 @@ function _populate_aggregated_service_model!(template::ProblemTemplate, sys::PSY PSY.get_name(service); use_slacks = use_slacks, duals = duals, + attributes = attributes, ), ) end From 3543aecae20c2f98f8784d35c544b0e03d9983cc Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 18:40:05 -0600 Subject: [PATCH 063/370] use reserves abstraction in reserves --- src/services_models/reserves.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/services_models/reserves.jl b/src/services_models/reserves.jl index 33988203cc..f02c13f619 100644 --- a/src/services_models/reserves.jl +++ b/src/services_models/reserves.jl @@ -66,7 +66,10 @@ function get_default_time_series_names( return Dict{Type{<:TimeSeriesParameter}, String}() end -function get_default_attributes(::Type{<:PSY.Reserve}, ::Type{<:AbstractReservesFormulation}) +function get_default_attributes( + ::Type{<:PSY.Reserve}, + ::Type{<:AbstractReservesFormulation}, +) return Dict{String, Any}() end From d66f2377c70cf2f6f38056415c851e79415d48cf Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 18:44:25 -0600 Subject: [PATCH 064/370] add constructor methods for interfaces --- src/services_models/services_constructor.jl | 44 ++++++++++----------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index 818c1ae52e..fd478750fc 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -66,7 +66,7 @@ function construct_services!( groupservice = key continue end - isempty(get_contributing_devices(service_model)) && continue + isempty(get_contributing_devices_map(service_model)) && continue construct_service!( container, sys, @@ -467,19 +467,20 @@ function construct_service!( container::OptimizationContainer, sys::PSY.System, ::ArgumentConstructStage, - model::ServiceModel{SR, ConstantMaxInterfaceFlow}, + model::ServiceModel{T, ConstantMaxInterfaceFlow}, devices_template::Dict{Symbol, DeviceModel}, incompatible_device_types::Set{<:DataType}, -) where {SR <: PSY.TransmissionInterface} - contributing_devices = get_contributing_devices(model) - add_to_expression!( +) where {T <: PSY.TransmissionInterface} + # contributing_devices_map = get_contributing_devices_map(model) + interfaces = PSY.get_name.(get_available_components(T, sys)) + lazy_container_addition!( container, - InterfaceTotalFlow, - FlowActivePowerVariable, - contributing_devices, - model, + InterfaceTotalFlow(), + T, + interfaces, + get_time_steps(container), ) - add_feedforward_arguments!(container, model, service) + #add_feedforward_arguments!(container, model, service) return end @@ -487,23 +488,22 @@ function construct_service!( container::OptimizationContainer, sys::PSY.System, ::ModelConstructStage, - model::ServiceModel{SR, ConstantMaxInterfaceFlow}, + model::ServiceModel{T, ConstantMaxInterfaceFlow}, devices_template::Dict{Symbol, DeviceModel}, incompatible_device_types::Set{<:DataType}, -) where {SR <: PSY.TransmissionInterface} - @error("here2") - error() +) where {T <: PSY.TransmissionInterface} name = get_service_name(model) - service = PSY.get_component(SR, sys, name) - contributing_devices = get_contributing_devices(model) - - add_constraints!(container, RequirementConstraint, service, contributing_devices, model) - - objective_function!(container, service, model) + service = PSY.get_component(T, sys, name) + add_to_expression!( + container, + InterfaceTotalFlow, + FlowActivePowerVariable, + service, + model, + ) + add_constraints!(container, InterfaceFlowLimit, service, model) add_feedforward_constraints!(container, model, service) - add_constraint_dual!(container, sys, model) - return end From 8a012e89060b30e792ca79647b946fe0a9095dfa Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 18:44:37 -0600 Subject: [PATCH 065/370] add methods for interface --- .../devices/common/add_to_expression.jl | 32 +++++++++++-------- src/feedforward/feedforward_constraints.jl | 15 ++++++++- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index a892466a48..3b61b16f47 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -757,24 +757,28 @@ function add_to_expression!( container::OptimizationContainer, ::Type{InterfaceTotalFlow}, ::Type{FlowActivePowerVariable}, - devices::Vector{T}, - model::ServiceModel{PSY.TransmissionInterface, ConstantMaxInterfaceFlow} -) where {T <: PSY.Component} - services = get_available_components(TransmissionInterface, sys) - if !has_container_key(container, InterfaceTotalFlow, TransmissionInterface) - add_expressions!(container, InterfaceTotalFlow, services, model) - end - variable = get_variable(container, FlowActivePowerVariable(), X, service_name) - - expression = get_expression(container, T(), V) - for d in devices, t in get_time_steps(container) - name = PSY.get_name(d) - _add_to_jump_expression!(expression[name, t], variable[name, t], 1.0) + service::PSY.TransmissionInterface, + model::ServiceModel{PSY.TransmissionInterface, ConstantMaxInterfaceFlow}, +) + expression = get_expression(container, InterfaceTotalFlow(), PSY.TransmissionInterface) + service_name = get_service_name(model) + for (device_type, devices) in get_contributing_devices_map(model) + variable = get_variable(container, FlowActivePowerVariable(), device_type) + for d in devices + name = PSY.get_name(d) + direction = get(PSY.get_direction_mapping(service), name, 1.0) + for t in get_time_steps(container) + _add_to_jump_expression!( + expression[service_name, t], + variable[name, t], + direction, + ) + end + end end return end - function add_to_expression!( container::OptimizationContainer, ::Type{T}, diff --git a/src/feedforward/feedforward_constraints.jl b/src/feedforward/feedforward_constraints.jl index 200f9988da..ee676f288d 100644 --- a/src/feedforward/feedforward_constraints.jl +++ b/src/feedforward/feedforward_constraints.jl @@ -12,7 +12,7 @@ end function add_feedforward_constraints!( container::OptimizationContainer, - model::ServiceModel, + model::ServiceModel{V, <:AbstractReservesFormulation}, ::V, ) where {V <: PSY.AbstractReserve} for ff in get_feedforwards(model) @@ -23,6 +23,19 @@ function add_feedforward_constraints!( return end +function add_feedforward_constraints!( + container::OptimizationContainer, + model::ServiceModel, + ::V, +) where {V <: PSY.Service} + for ff in get_feedforwards(model) + @debug "constraints" ff V _group = LOG_GROUP_FEEDFORWARDS_CONSTRUCTION + contributing_devices = get_contributing_devices(model) + add_feedforward_constraints!(container, model, contributing_devices, ff) + end + return +end + function _add_feedforward_constraints!( container::OptimizationContainer, ::Type{T}, From f7ef29a68d74994ee47a0c7f60d7b15cdb625faa Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 18:44:47 -0600 Subject: [PATCH 066/370] implement interface constraints --- src/services_models/transmission_interface.jl | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/services_models/transmission_interface.jl b/src/services_models/transmission_interface.jl index a8c6edb350..add9e99104 100644 --- a/src/services_models/transmission_interface.jl +++ b/src/services_models/transmission_interface.jl @@ -17,3 +17,37 @@ function get_initial_conditions_service_model( ) where {T <: PSY.TransmissionInterface, D <: ConstantMaxInterfaceFlow} return ServiceModel(T, D) end + +function add_constraints!(container::OptimizationContainer, + ::Type{InterfaceFlowLimit}, + interface::T, + model::ServiceModel{T, ConstantMaxInterfaceFlow}, +) where {T <: PSY.TransmissionInterface} + expr = get_expression(container, InterfaceTotalFlow(), T) + interfaces, timesteps = axes(expr) + constraint_container_ub = lazy_container_addition!( + container, + InterfaceFlowLimit(), + T, + interfaces, + timesteps; + meta = "ub", + ) + constraint_container_lb = lazy_container_addition!( + container, + InterfaceFlowLimit(), + T, + interfaces, + timesteps; + meta = "lb", + ) + int_name = PSY.get_name(interface) + min_flow, max_flow = PSY.get_active_power_flow_limits(interface) + for t in timesteps + constraint_container_ub[int_name, t] = + JuMP.@constraint(get_jump_model(container), expr[int_name, t] <= max_flow) + constraint_container_lb[int_name, t] = + JuMP.@constraint(get_jump_model(container), expr[int_name, t] >= min_flow) + end + return +end From 0423eb51bef9d94bc2fd133e7d25a57d1c684bce Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 24 May 2023 13:09:21 -0600 Subject: [PATCH 067/370] update deps --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index b65bf62e24..967ce8b0b6 100644 --- a/Project.toml +++ b/Project.toml @@ -43,7 +43,7 @@ JuMP = "1" MathOptInterface = "1" PowerModels = "~0.19" PowerNetworkMatrices = "^0.7" -PowerSystems = "2" +PowerSystems = "^2.3" PrettyTables = "^1.3, 2" ProgressMeter = "^1.5" TimeSeries = "~0.23" From f63fcbbf1b6cf7e0bf3c9a4eb91dee61ac1418f7 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 14 Jun 2023 12:12:20 -0600 Subject: [PATCH 068/370] fix group reserves --- src/PowerSimulations.jl | 1 + src/services_models/agc.jl | 14 ++++++++++++++ src/services_models/reserve_group.jl | 11 +++++++++++ src/services_models/reserves.jl | 18 ++++++++++++++++-- test/test_basic_model_structs.jl | 4 ++-- 5 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 src/services_models/reserve_group.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 5155090bf9..4b8e7a643f 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -541,6 +541,7 @@ include("devices_models/devices/regulation_device.jl") # Services Models include("services_models/agc.jl") include("services_models/reserves.jl") +include("services_models/reserve_group.jl") include("services_models/transmission_interface.jl") include("services_models/group_reserve.jl") include("services_models/service_slacks.jl") diff --git a/src/services_models/agc.jl b/src/services_models/agc.jl index 3de0ddffdf..3ad04e7799 100644 --- a/src/services_models/agc.jl +++ b/src/services_models/agc.jl @@ -45,6 +45,20 @@ get_variable_multiplier(::SteadyStateFrequencyDeviation, d::PSY.AGC, ::AbstractA #! format: on +function get_default_time_series_names( + ::Type{PSY.AGC}, + ::Type{<:AbstractAGCFormulation}, +) + return Dict{Type{<:TimeSeriesParameter}, String}() +end + +function get_default_attributes( + ::Type{PSY.AGC}, + ::Type{<:AbstractAGCFormulation}, +) + return Dict{String, Any}() +end + """ Steady State deviation of the frequency """ diff --git a/src/services_models/reserve_group.jl b/src/services_models/reserve_group.jl new file mode 100644 index 0000000000..b64e1613a7 --- /dev/null +++ b/src/services_models/reserve_group.jl @@ -0,0 +1,11 @@ +function get_default_time_series_names( + ::Type{PSY.StaticReserveGroup{T}}, + ::Type{GroupReserve}) where {T <: PSY.ReserveDirection} + return Dict{String, Any}() +end + +function get_default_attributes( + ::Type{PSY.StaticReserveGroup{T}}, + ::Type{GroupReserve}) where {T <: PSY.ReserveDirection} + return Dict{String, Any}() +end diff --git a/src/services_models/reserves.jl b/src/services_models/reserves.jl index f02c13f619..f97ed1f2a1 100644 --- a/src/services_models/reserves.jl +++ b/src/services_models/reserves.jl @@ -41,6 +41,13 @@ function get_initial_conditions_service_model( return ServiceModel(T, D) end +function get_initial_conditions_service_model( + ::OperationModel, + ::ServiceModel{T, D}, +) where {T <: PSY.VariableReserveNonSpinning, D <: AbstractReservesFormulation} + return ServiceModel(T, D) +end + function get_default_time_series_names( ::Type{<:PSY.Reserve}, ::Type{T}, @@ -60,9 +67,9 @@ function get_default_time_series_names( end function get_default_time_series_names( - ::Type{<:PSY.Reserve}, + ::Type{T}, ::Type{<:AbstractReservesFormulation}, -) +) where {T <: PSY.Reserve} return Dict{Type{<:TimeSeriesParameter}, String}() end @@ -73,6 +80,13 @@ function get_default_attributes( return Dict{String, Any}() end +function get_default_attributes( + ::Type{<:PSY.ReserveNonSpinning}, + ::Type{<:AbstractReservesFormulation}, +) + return Dict{String, Any}() +end + ################################## Reserve Requirement Constraint ########################## function add_constraints!( container::OptimizationContainer, diff --git a/test/test_basic_model_structs.jl b/test/test_basic_model_structs.jl index 865705f8fa..6928b5e196 100644 --- a/test/test_basic_model_structs.jl +++ b/test/test_basic_model_structs.jl @@ -9,10 +9,10 @@ end end @testset "ServiceModel Tests" begin - @test_throws ArgumentError ServiceModel(AGC, PSI.AbstractServiceFormulation, "TestName") + @test_throws ArgumentError ServiceModel(AGC, PSI.AbstractAGCFormulation, "TestName") @test_throws ArgumentError ServiceModel( VariableReserve{PSY.ReserveUp}, - PSI.AbstractServiceFormulation, + PSI.AbstractReservesFormulation, "TestName2", ) end From 0e67cbd2b356115bda6969b329091c9c081069f7 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 15 Jun 2023 17:07:47 -0600 Subject: [PATCH 069/370] fix bug --- src/core/network_model.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/network_model.jl b/src/core/network_model.jl index 07b514fd76..923e9c735b 100644 --- a/src/core/network_model.jl +++ b/src/core/network_model.jl @@ -48,7 +48,7 @@ end get_use_slacks(m::NetworkModel) = m.use_slacks get_PTDF_matrix(m::NetworkModel) = m.PTDF_matrix get_duals(m::NetworkModel) = m.duals -get_network_formulation(::NetworkModel{T}) where {T <: PM.AbstractPowerModel} = T +get_network_formulation(::NetworkModel{T}) where {T} = T get_reference_buses(m::NetworkModel{T}) where {T <: PM.AbstractPowerModel} = collect(keys(m.subnetworks)) get_subnetworks(m::NetworkModel) = m.subnetworks From 21eb5737b3cbe416fc12ae58a7280345ef6e8833 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 15 Jun 2023 17:07:53 -0600 Subject: [PATCH 070/370] add slacks for interface --- src/core/variables.jl | 6 +++ .../devices/common/add_to_expression.jl | 20 ++++++++++ src/services_models/services_constructor.jl | 40 +++++++++++++++++-- src/services_models/transmission_interface.jl | 32 +++++++++++++++ 4 files changed, 95 insertions(+), 3 deletions(-) diff --git a/src/core/variables.jl b/src/core/variables.jl index 852bed4ab8..da3d779a8b 100644 --- a/src/core/variables.jl +++ b/src/core/variables.jl @@ -213,6 +213,10 @@ struct HVDCFlowDirectionVariable <: VariableType end struct PieceWiseLinearCostVariable <: VariableType end +struct InterfaceFlowSlackUp <: VariableType end + +struct InterfaceFlowSlackDown <: VariableType end + const START_VARIABLES = (HotStartVariable, WarmStartVariable, ColdStartVariable) should_write_resulting_value(::Type{<:VariableType}) = true @@ -248,3 +252,5 @@ convert_result_to_natural_units(::Type{FlowActivePowerToFromVariable}) = true convert_result_to_natural_units(::Type{FlowReactivePowerFromToVariable}) = true convert_result_to_natural_units(::Type{FlowReactivePowerToFromVariable}) = true convert_result_to_natural_units(::Type{HVDCLosses}) = true +convert_result_to_natural_units(::Type{InterfaceFlowSlackUp}) = true +convert_result_to_natural_units(::Type{InterfaceFlowSlackDown}) = true diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 3b61b16f47..fb75c61de2 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -753,6 +753,26 @@ function add_to_expression!( return end +function add_to_expression!( + container::OptimizationContainer, + ::Type{InterfaceTotalFlow}, + ::Type{T}, + service::PSY.TransmissionInterface, + model::ServiceModel{PSY.TransmissionInterface, ConstantMaxInterfaceFlow}, +) where {T <: Union{InterfaceFlowSlackUp, InterfaceFlowSlackDown}} + expression = get_expression(container, InterfaceTotalFlow(), PSY.TransmissionInterface) + variable = get_variable(container, T(), PSY.TransmissionInterface) + service_name=PSY.get_name(service) + for t in get_time_steps(container) + _add_to_jump_expression!( + expression[service_name, t], + variable[service_name, t], + get_variable_multiplier(T(), service, ConstantMaxInterfaceFlow()), + ) + end + return +end + function add_to_expression!( container::OptimizationContainer, ::Type{InterfaceTotalFlow}, diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index fd478750fc..e46cb76a3f 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -471,13 +471,28 @@ function construct_service!( devices_template::Dict{Symbol, DeviceModel}, incompatible_device_types::Set{<:DataType}, ) where {T <: PSY.TransmissionInterface} - # contributing_devices_map = get_contributing_devices_map(model) - interfaces = PSY.get_name.(get_available_components(T, sys)) + interfaces = get_available_components(T, sys) + # Lazy container addition for the expressions. + if get_use_slacks(model) + add_variables!( + container, + InterfaceFlowSlackUp, + interfaces, + ConstantMaxInterfaceFlow() + ) + add_variables!( + container, + InterfaceFlowSlackDown, + interfaces, + ConstantMaxInterfaceFlow() + ) + end + lazy_container_addition!( container, InterfaceTotalFlow(), T, - interfaces, + PSY.get_name.(interfaces), get_time_steps(container), ) #add_feedforward_arguments!(container, model, service) @@ -502,8 +517,27 @@ function construct_service!( service, model, ) + + if get_use_slacks(model) + add_to_expression!( + container, + InterfaceTotalFlow, + InterfaceFlowSlackUp, + service, + model, + ) + add_to_expression!( + container, + InterfaceTotalFlow, + InterfaceFlowSlackDown, + service, + model, + ) + end + add_constraints!(container, InterfaceFlowLimit, service, model) add_feedforward_constraints!(container, model, service) add_constraint_dual!(container, sys, model) + objective_function!(container, service, model) return end diff --git a/src/services_models/transmission_interface.jl b/src/services_models/transmission_interface.jl index add9e99104..53643ce152 100644 --- a/src/services_models/transmission_interface.jl +++ b/src/services_models/transmission_interface.jl @@ -1,3 +1,12 @@ +#! format: off +get_variable_binary(_, ::Type{PSY.TransmissionInterface}, ::ConstantMaxInterfaceFlow) = false +get_variable_lower_bound(::InterfaceFlowSlackUp, ::PSY.TransmissionInterface, ::ConstantMaxInterfaceFlow) = 0.0 +get_variable_lower_bound(::InterfaceFlowSlackDown, ::PSY.TransmissionInterface, ::ConstantMaxInterfaceFlow) = 0.0 + +get_variable_multiplier(::InterfaceFlowSlackUp, ::PSY.TransmissionInterface, ::ConstantMaxInterfaceFlow) = 1.0 +get_variable_multiplier(::InterfaceFlowSlackDown, ::PSY.TransmissionInterface, ::ConstantMaxInterfaceFlow) = -1.0 + +#! format: On function get_default_time_series_names( ::Type{PSY.TransmissionInterface}, ::Type{ConstantMaxInterfaceFlow}, @@ -18,6 +27,8 @@ function get_initial_conditions_service_model( return ServiceModel(T, D) end + + function add_constraints!(container::OptimizationContainer, ::Type{InterfaceFlowLimit}, interface::T, @@ -51,3 +62,24 @@ function add_constraints!(container::OptimizationContainer, end return end + +function objective_function!( + container::OptimizationContainer, + service::T, + model::ServiceModel{T, U}, +) where {T <: PSY.TransmissionInterface, U <: ConstantMaxInterfaceFlow} + # At the moment the interfaces have no costs associated with them + if get_use_slacks(model) + variable_up = get_variable(container, InterfaceFlowSlackDown(), T) + variable_dn = get_variable(container, InterfaceFlowSlackDown(), T) + penalty = PSY.get_violation_penalty(service) + name = PSY.get_name(service) + for t in get_time_steps(container) + add_to_objective_invariant_expression!( + container, + (variable_dn[name, t] + variable_up[name, t]) * penalty, + ) + end + end + return +end From 0f129ca0c605af7f5dccf325e6e86765b88d7c78 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 15 Jun 2023 17:09:35 -0600 Subject: [PATCH 071/370] formatter --- src/devices_models/devices/common/add_to_expression.jl | 2 +- src/services_models/services_constructor.jl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index fb75c61de2..f7cc493296 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -762,7 +762,7 @@ function add_to_expression!( ) where {T <: Union{InterfaceFlowSlackUp, InterfaceFlowSlackDown}} expression = get_expression(container, InterfaceTotalFlow(), PSY.TransmissionInterface) variable = get_variable(container, T(), PSY.TransmissionInterface) - service_name=PSY.get_name(service) + service_name = PSY.get_name(service) for t in get_time_steps(container) _add_to_jump_expression!( expression[service_name, t], diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index e46cb76a3f..c65a61d45f 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -478,13 +478,13 @@ function construct_service!( container, InterfaceFlowSlackUp, interfaces, - ConstantMaxInterfaceFlow() + ConstantMaxInterfaceFlow(), ) add_variables!( container, InterfaceFlowSlackDown, interfaces, - ConstantMaxInterfaceFlow() + ConstantMaxInterfaceFlow(), ) end From 2c1c220126a93f48bc1e207854e8bdba92a8f31e Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 14 Apr 2023 16:32:50 -0700 Subject: [PATCH 072/370] update docstring for DeviceModel --- src/core/device_model.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/core/device_model.jl b/src/core/device_model.jl index b5604e0876..605007018c 100644 --- a/src/core/device_model.jl +++ b/src/core/device_model.jl @@ -27,6 +27,10 @@ feedforward to enable passing values between operation model at simulation time # Accepted Key Words - `feedforward::Array{<:AbstractAffectFeedforward}` : use to pass parameters between models + - `use_slacks::Bool : Add slacks to the device model` + - `duals::Vector{DataType} : use to pass constraint type to calculate the duals` + - `time_series_names::Dict{Type{<:TimeSeriesParameter}, String} : use to specify time series names associated to the device` + - `attributes::Dict{String, Any} : use to specify attributes to the device` # Example From b546af99ba20814d39e3e184bc8b02e510eefb95 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 14 Apr 2023 16:32:58 -0700 Subject: [PATCH 073/370] update docstring for decision models --- src/operation/decision_model.jl | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index 0951114934..90558381c0 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -280,7 +280,19 @@ end get_horizon(model::DecisionModel) = get_horizon(get_settings(model)) """ -Implementation of build for any DecisionProblem +Build the Decision Model based on the specified DecisionProblem. + +# Arguments + + - `model::DecisionModel{<:DecisionProblem}`: DecisionModel object + - `output_dir::String`: Output directory for results + +# Accepted Key Words + + - `recorders::Vector{Symbol} = []`: recorder names to register + - `console_level = Logging.Error`: + - `file_level = Logging.Info`: + - `disable_timer_outputs = false` : Enable/Disable timing outputs """ function build!( model::DecisionModel{<:DecisionProblem}; @@ -359,15 +371,20 @@ keyword arguments to that function. # Arguments - `model::OperationModel = model`: operation model - - `optimizer::MOI.OptimizerWithAttributes`: The optimizer that is used to solve the model - - `export_problem_results::Bool`: If true, export ProblemResults DataFrames to CSV files. - - `serialize::Bool`: If true, serialize the model to a file to allow re-execution later. + +# Accepted Key Words + + - `export_problem_results::Bool = false`: If true, export ProblemResults DataFrames to CSV files. + - `console_level = Logging.Error`: + - `file_level = Logging.Info`: + - `disable_timer_outputs = false` : Enable/Disable timing outputs + - `serialize::Bool = true`: If true, serialize the model to a file to allow re-execution later. # Examples ```julia results = solve!(OpModel) -results = solve!(OpModel, output_dir="output") +results = solve!(OpModel, export_problem_results = true) ``` """ function solve!( From d86aa90eb8cafc490edaf76ba3bc941c2fcebef3 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 14 Apr 2023 16:33:10 -0700 Subject: [PATCH 074/370] update API markdown --- docs/src/api/PowerSimulations.md | 33 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index f0edb4354f..fd49ece3e3 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -1,5 +1,3 @@ -# PowerSimulations - ```@meta CurrentModule = PowerSimulations DocTestSetup = quote @@ -7,29 +5,22 @@ DocTestSetup = quote end ``` -API documentation - -```@contents -Pages = ["PowerSimulations.md"] -``` +# Device Models -## Index +List of structures and methods for Device models -```@index -Pages = ["PowerSimulations.md"] +```@docs +DeviceModel ``` -## Exported +### Formulations -```@autodocs -Modules = [PowerSimulations] -Private = false -Filter = t -> typeof(t) === DataType ? !(t <: Union{PowerSimulations.AbstractDeviceFormulation, PowerSimulations.AbstractServiceFormulation}) : true -``` +Refer to the Formulations Page for each Abstract Device Formulation. -## Internal +# Decision Models -```@autodocs -Modules = [PowerSimulations] -Public = false -``` +```@docs +DecisionModel +build!(::DecisionModel) +solve!(::DecisionModel) +``` \ No newline at end of file From 1252bed5bde3082cd62fb2463a64042e3802bdb4 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Thu, 20 Apr 2023 17:20:07 -0700 Subject: [PATCH 075/370] update docstrings --- docs/src/api/PowerSimulations.md | 19 ++++++- src/PowerSimulations.jl | 1 - src/core/device_model.jl | 32 ++++++----- src/operation/decision_model.jl | 91 +++++++++++--------------------- 4 files changed, 69 insertions(+), 74 deletions(-) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index fd49ece3e3..7eaba36ca0 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -5,6 +5,16 @@ DocTestSetup = quote end ``` +# API Reference + + +### Table of Contents + +1. [Device Models](#Device-Models) +2. [Decision Models](#Decision-Models) + + + # Device Models List of structures and methods for Device models @@ -15,12 +25,19 @@ DeviceModel ### Formulations -Refer to the Formulations Page for each Abstract Device Formulation. +Refer to the [Formulations Page](https://nrel-siip.github.io/PowerSimulations.jl/latest/formulation_library/General/) for each Abstract Device Formulation. + +```@raw html +  +  +``` # Decision Models ```@docs DecisionModel +DecisionModel(::Type{M} where {M <: DecisionProblem}, ::ProblemTemplate, ::PSY.System, ::Union{Nothing, JuMP.Model}) +DecisionModel(::AbstractString, ::MOI.OptimizerWithAttributes) build!(::DecisionModel) solve!(::DecisionModel) ``` \ No newline at end of file diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 0f3babea93..4594615521 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -436,7 +436,6 @@ using DocStringExtensions @template DEFAULT = """ $(TYPEDSIGNATURES) $(DOCSTRING) - $(METHODLIST) """ # Includes diff --git a/src/core/device_model.jl b/src/core/device_model.jl index 605007018c..8775969d32 100644 --- a/src/core/device_model.jl +++ b/src/core/device_model.jl @@ -16,25 +16,33 @@ function _check_device_formulation( end """ + DeviceModel( + ::Type{D}, + ::Type{B}, + feedforwards::Vector{<:AbstractAffectFeedforward} + use_slacks::Bool, + duals::Vector{DataType}, + services::Vector{ServiceModel} + attributes::Dict{String, Any} + ) + Establishes the model for a particular device specified by type. Uses the keyword argument feedforward to enable passing values between operation model at simulation time # Arguments --`::Type{D}`: Power System Device Type --`::Type{B}`: Abstract Device Formulation - -# Accepted Key Words - - - `feedforward::Array{<:AbstractAffectFeedforward}` : use to pass parameters between models - - `use_slacks::Bool : Add slacks to the device model` - - `duals::Vector{DataType} : use to pass constraint type to calculate the duals` - - `time_series_names::Dict{Type{<:TimeSeriesParameter}, String} : use to specify time series names associated to the device` - - `attributes::Dict{String, Any} : use to specify attributes to the device` + - `::Type{D}`: Power System Device Type + - `::Type{B}`: Abstract Device Formulation + - `feedforward::Array{<:AbstractAffectFeedforward} = Vector{AbstractAffectFeedforward}()` : use to pass parameters between models + - `use_slacks::Bool = false` : Add slacks to the device model + - `duals::Vector{DataType} = Vector{DataType}()`: use to pass constraint type to calculate the duals + - `time_series_names::Dict{Type{<:TimeSeriesParameter}, String} = get_default_time_series_names(D, B)` : use to specify time series names associated to the device` + - `attributes::Dict{String, Any} = get_default_attributes(D, B)` : use to specify attributes to the device # Example - -thermal_gens = DeviceModel(ThermalStandard, ThermalBasicUnitCommitment), +```julia +thermal_gens = DeviceModel(ThermalStandard, ThermalBasicUnitCommitment) +``` """ mutable struct DeviceModel{D <: PSY.Device, B <: AbstractDeviceFormulation} feedforwards::Vector{<:AbstractAffectFeedforward} diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index 90558381c0..99ad91833c 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -4,47 +4,47 @@ Default PowerSimulations Operation Problem Type struct GenericOpProblem <: DecisionProblem end """ - DecisionModel(::Type{M}, - template::ProblemTemplate, - sys::PSY.System, - jump_model::Union{Nothing, JuMP.Model}=nothing; - kwargs...) where {M<:DecisionProblem, - T<:PM.AbstractPowerFormulation} + DecisionModel{M}( + template::ProblemTemplate, + sys::PSY.System, + jump_model::Union{Nothing, JuMP.Model}=nothing; + kwargs...) where {M<:DecisionProblem, + T<:PM.AbstractPowerFormulation} This builds the optimization problem of type M with the specific system and template. # Arguments - `::Type{M} where M<:DecisionProblem`: The abstract operation model type - - `template::ProblemTemplate`: The model reference made up of transmission, devices, - branches, and services. + - `template::ProblemTemplate`: The model reference made up of transmission, devices, branches, and services. - `sys::PSY.System`: the system created using Power Systems - `jump_model::Union{Nothing, JuMP.Model}`: Enables passing a custom JuMP model. Use with care - -# Output - - - `model::DecisionModel`: The operation model containing the model type, built JuMP model, Power - Systems system. + - `name = nothing`: name of model, string or symbol; defaults to the type of template converted to a symbol. + - `optimizer::Union{Nothing,MOI.OptimizerWithAttributes} = nothing` : The optimizer does + not get serialized. Callers should pass whatever they passed to the original problem. + - `horizon::Int = UNSET_HORIZON`: Manually specify the length of the forecast Horizon + - `warm_start::Bool = true`: True will use the current operation point in the system to initialize variable values. False initializes all variables to zero. Default is true + - `system_to_file::Bool = true:`: True to create a copy of the system used in the model. + - `initialize_model::Bool = true`: Option to decide to initialize the model or not. + - `initialization_file::String = ""`: TODO + - `deserialize_initial_conditions::Bool = false`: Option to deserialize conditions + - `export_pwl_vars::Bool = false`: True to export all the pwl intermediate variables. It can slow down significantly the solve time. + - `allow_fails::Bool = false`: True to allow the simulation to continue even if the optimization step fails. Use with care. + - `optimizer_solve_log_print::Bool = false`: Uses JuMP.unset_silent() to print the optimizer's log. By default all solvers are set to MOI.Silent() + - `detailed_optimizer_stats::Bool = false`: True to save detailed optimizer stats log. + - `calculate_conflict::Bool = false`: True to use solver to calculate conflicts for infeasible problems. Only specific solvers are able to calculate conflicts. + - `direct_mode_optimizer::Bool = false`: True to use the solver in direct mode. Creates a [JuMP.direct_model](https://jump.dev/JuMP.jl/dev/reference/models/#JuMP.direct_model). + - `store_variable_names::Bool = false`: True to store variable names in optimization model. + - `rebuild_model::Bool = false`: TODO + - `initial_time::Dates.DateTime = UNSET_INI_TIME`: Initial Time for the model solve. + - `time_series_cache_size::Int = IS.TIME_SERIES_CACHE_SIZE_BYTES`: Size in bytes to cache for each time array. Default is 1 MiB. Set to 0 to disable. # Example ```julia template = ProblemTemplate(CopperPlatePowerModel, devices, branches, services) OpModel = DecisionModel(MockOperationProblem, template, system) -``` - -# Accepted Key Words - - - `optimizer`: The optimizer that will be used in the optimization model. - - `horizon::Int`: Manually specify the length of the forecast Horizon - - `warm_start::Bool`: True will use the current operation point in the system to initialize variable values. False initializes all variables to zero. Default is true - - `system_to_file::Bool:`: True to create a copy of the system used in the model. Default true. - - `export_pwl_vars::Bool`: True to export all the pwl intermediate variables. It can slow down significantly the solve time. Default is false. - - `allow_fails::Bool`: True to allow the simulation to continue even if the optimization step fails. Use with care, default to false. - - `optimizer_solve_log_print::Bool`: True to print the optimizer solve log. Default is false. - - `direct_mode_optimizer::Bool` True to use the solver in direct mode. Creates a [JuMP.direct_model](https://jump.dev/JuMP.jl/dev/reference/models/#JuMP.direct_model). Default is false. - - `initial_time::Dates.DateTime`: Initial Time for the model solve - - `time_series_cache_size::Int`: Size in bytes to cache for each time array. Default is 1 MiB. Set to 0 to disable. +``` """ mutable struct DecisionModel{M <: DecisionProblem} <: OperationModel name::Symbol @@ -136,41 +136,20 @@ function DecisionModel{M}( end """ - DecisionModel(::Type{M}, - template::ProblemTemplate, - sys::PSY.System, - optimizer::MOI.OptimizerWithAttributes, - jump_model::Union{Nothing, JuMP.Model}=nothing; - kwargs...) where {M <: DecisionProblem} - This builds the optimization problem of type M with the specific system and template # Arguments - `::Type{M} where M<:DecisionProblem`: The abstract operation model type - - `template::ProblemTemplate`: The model reference made up of transmission, devices, - branches, and services. + - `template::ProblemTemplate`: The model reference made up of transmission, devices, branches, and services. - `sys::PSY.System`: the system created using Power Systems - - `jump_model::Union{Nothing, JuMP.Model}`: Enables passing a custom JuMP model. Use with care - -# Output - - - `Stage::DecisionProblem`: The operation model containing the model type, unbuilt JuMP model, Power - Systems system. + - `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) - -``` -# Accepted Key Words -- `initial_time::Dates.DateTime`: Initial Time for the model solve -- `warm_start::Bool` True will use the current operation point in the system to initialize variable values. False initializes all variables to zero. Default is true -- `export_pwl_vars::Bool` True will write the results of the piece-wise-linear intermediate variables. Slows down the simulation process significantly -- `allow_fails::Bool` True will allow the simulation to continue if the optimizer can't find a solution. Use with care, can lead to unwanted behaviour or results -- `optimizer_solve_log_print::Bool` Uses JuMP.unset_silent() to print the optimizer's log. By default all solvers are set to `MOI.Silent()` -- `name`: name of model, string or symbol; defaults to the type of template converted to a symbol +problem = DecisionModel(MyOpProblemType, template, system, optimizer) ``` """ function DecisionModel( @@ -193,8 +172,6 @@ function DecisionModel( end """ - DecisionModel(directory::AbstractString) - Construct an DecisionProblem from a serialized file. # Arguments @@ -286,9 +263,6 @@ Build the Decision Model based on the specified DecisionProblem. - `model::DecisionModel{<:DecisionProblem}`: DecisionModel object - `output_dir::String`: Output directory for results - -# Accepted Key Words - - `recorders::Vector{Symbol} = []`: recorder names to register - `console_level = Logging.Error`: - `file_level = Logging.Info`: @@ -371,9 +345,6 @@ keyword arguments to that function. # Arguments - `model::OperationModel = model`: operation model - -# Accepted Key Words - - `export_problem_results::Bool = false`: If true, export ProblemResults DataFrames to CSV files. - `console_level = Logging.Error`: - `file_level = Logging.Info`: From 91ffa1ae554aadfafd19c53c4006dc227f8d9fae Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Thu, 20 Apr 2023 17:24:22 -0700 Subject: [PATCH 076/370] add problem templates link --- docs/src/api/PowerSimulations.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index 7eaba36ca0..8dd2365793 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -27,6 +27,10 @@ DeviceModel Refer to the [Formulations Page](https://nrel-siip.github.io/PowerSimulations.jl/latest/formulation_library/General/) for each Abstract Device Formulation. +### Problem Templates + +Refer to the [Problem Templates Page](https://nrel-siip.github.io/PowerSimulations.jl/latest/modeler_guide/problem_templates/) for available `ProblemTemplate`s. + ```@raw html     From ccc8b62ef5d4d1f9b929988ff1a7645aaa3ed43c Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 21 Apr 2023 13:13:01 -0700 Subject: [PATCH 077/370] add emulation models --- docs/src/api/PowerSimulations.md | 17 ++++++- src/core/device_model.jl | 4 +- src/operation/decision_model.jl | 3 +- src/operation/emulation_model.jl | 87 ++++++++++++-------------------- 4 files changed, 52 insertions(+), 59 deletions(-) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index 8dd2365793..ae3ca22203 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -12,7 +12,7 @@ end 1. [Device Models](#Device-Models) 2. [Decision Models](#Decision-Models) - +3. [Emulation Models](#Emulation-Models) # Device Models @@ -44,4 +44,19 @@ DecisionModel(::Type{M} where {M <: DecisionProblem}, ::ProblemTemplate, ::PSY.S DecisionModel(::AbstractString, ::MOI.OptimizerWithAttributes) build!(::DecisionModel) solve!(::DecisionModel) +``` + +```@raw html +  +  +``` + +# Emulation Models + +```@docs +EmulationModel +EmulationModel(::Type{M} where {M <: EmulationProblem}, ::ProblemTemplate, ::PSY.System, ::Union{Nothing, JuMP.Model}) +EmulationModel(::AbstractString, ::MOI.OptimizerWithAttributes) +build!(::EmulationModel) +run!(::EmulationModel) ``` \ No newline at end of file diff --git a/src/core/device_model.jl b/src/core/device_model.jl index 8775969d32..6324a3d30f 100644 --- a/src/core/device_model.jl +++ b/src/core/device_model.jl @@ -31,8 +31,8 @@ feedforward to enable passing values between operation model at simulation time # Arguments - - `::Type{D}`: Power System Device Type - - `::Type{B}`: Abstract Device Formulation + - `::Type{D} where D<:PSY.Device`: Power System Device Type + - `::Type{B} where B<:AbstractDeviceFormulation`: Abstract Device Formulation - `feedforward::Array{<:AbstractAffectFeedforward} = Vector{AbstractAffectFeedforward}()` : use to pass parameters between models - `use_slacks::Bool = false` : Add slacks to the device model - `duals::Vector{DataType} = Vector{DataType}()`: use to pass constraint type to calculate the duals diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index 99ad91833c..120d8ef767 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -8,8 +8,7 @@ struct GenericOpProblem <: DecisionProblem end template::ProblemTemplate, sys::PSY.System, jump_model::Union{Nothing, JuMP.Model}=nothing; - kwargs...) where {M<:DecisionProblem, - T<:PM.AbstractPowerFormulation} + kwargs...) where {M<:DecisionProblem} This builds the optimization problem of type M with the specific system and template. diff --git a/src/operation/emulation_model.jl b/src/operation/emulation_model.jl index 88bf148a8e..b55aef670b 100644 --- a/src/operation/emulation_model.jl +++ b/src/operation/emulation_model.jl @@ -4,44 +4,45 @@ Default PowerSimulations Emulation Problem Type struct GenericEmulationProblem <: EmulationProblem end """ - EmulationModel(::Type{M}, - template::ProblemTemplate, - sys::PSY.System, - jump_model::Union{Nothing, JuMP.Model}=nothing; - kwargs...) where {M<:EmulationProblem, - T<:PM.AbstractPowerFormulation} + EmulationModel{M}( + template::ProblemTemplate, + sys::PSY.System, + jump_model::Union{Nothing, JuMP.Model}=nothing; + kwargs...) where {M<:EmulationProblem} This builds the optimization problem of type M with the specific system and template. # Arguments - `::Type{M} where M<:EmulationProblem`: The abstract Emulation model type - - `template::ProblemTemplate`: The model reference made up of transmission, devices, - branches, and services. + - `template::ProblemTemplate`: The model reference made up of transmission, devices, branches, and services. - `sys::PSY.System`: the system created using Power Systems - `jump_model::Union{Nothing, JuMP.Model}`: Enables passing a custom JuMP model. Use with care - -# Output - - - `model::EmulationModel`: The Emulation model containing the model type, built JuMP model, Power - Systems system. - + - `name = nothing`: name of model, string or symbol; defaults to the type of template converted to a symbol. + - `optimizer::Union{Nothing,MOI.OptimizerWithAttributes} = nothing` : The optimizer does + not get serialized. Callers should pass whatever they passed to the original problem. + - `warm_start::Bool = true`: True will use the current operation point in the system to initialize variable values. False initializes all variables to zero. Default is true + - `system_to_file::Bool = true:`: True to create a copy of the system used in the model. + - `initialize_model::Bool = true`: Option to decide to initialize the model or not. + - `initialization_file::String = ""`: TODO + - `deserialize_initial_conditions::Bool = false`: Option to deserialize conditions + - `export_pwl_vars::Bool = false`: True to export all the pwl intermediate variables. It can slow down significantly the solve time. + - `allow_fails::Bool = false`: True to allow the simulation to continue even if the optimization step fails. Use with care. + - `calculate_conflict::Bool = false`: True to use solver to calculate conflicts for infeasible problems. Only specific solvers are able to calculate conflicts. + - `optimizer_solve_log_print::Bool = false`: Uses JuMP.unset_silent() to print the optimizer's log. By default all solvers are set to MOI.Silent() + - `detailed_optimizer_stats::Bool = false`: True to save detailed optimizer stats log. + - `direct_mode_optimizer::Bool = false`: True to use the solver in direct mode. Creates a [JuMP.direct_model](https://jump.dev/JuMP.jl/dev/reference/models/#JuMP.direct_model). + - `store_variable_names::Bool = false`: True to store variable names in optimization model. + - `rebuild_model::Bool = false`: TODO + - `initial_time::Dates.DateTime = UNSET_INI_TIME`: Initial Time for the model solve. + - `time_series_cache_size::Int = IS.TIME_SERIES_CACHE_SIZE_BYTES`: Size in bytes to cache for each time array. Default is 1 MiB. Set to 0 to disable. + # Example +```julia template = ProblemTemplate(CopperPlatePowerModel, devices, branches, services) OpModel = EmulationModel(MockEmulationProblem, template, system) - -# Accepted Key Words - - - `optimizer`: The optimizer that will be used in the optimization model. - - `warm_start::Bool`: True will use the current Emulation point in the system to initialize variable values. False initializes all variables to zero. Default is true - - `system_to_file::Bool:`: True to create a copy of the system used in the model. Default true. - - `export_pwl_vars::Bool`: True to export all the pwl intermediate variables. It can slow down significantly the solve time. Default is false. - - `allow_fails::Bool`: True to allow the simulation to continue even if the optimization step fails. Use with care, default to false. - - `optimizer_solve_log_print::Bool`: True to print the optimizer solve log. Default is false. - - `direct_mode_optimizer::Bool` True to use the solver in direct mode. Creates a [JuMP.direct_model](https://jump.dev/JuMP.jl/dev/reference/models/#JuMP.direct_model). Default is false. - - `initial_time::Dates.DateTime`: Initial Time for the model solve - - `time_series_cache_size::Int`: Size in bytes to cache for each time array. Default is 1 MiB. Set to 0 to disable. +``` """ mutable struct EmulationModel{M <: EmulationProblem} <: OperationModel name::Symbol @@ -125,13 +126,6 @@ function EmulationModel{M}( end """ - EmulationModel(::Type{M}, - template::ProblemTemplate, - sys::PSY.System, - optimizer::MOI.OptimizerWithAttributes, - jump_model::Union{Nothing, JuMP.Model}=nothing; - kwargs...) where {M <: EmulationProblem} - This builds the optimization problem of type M with the specific system and template # Arguments @@ -142,24 +136,12 @@ This builds the optimization problem of type M with the specific system and temp - `sys::PSY.System`: the system created using Power Systems - `jump_model::Union{Nothing, JuMP.Model}`: Enables passing a custom JuMP model. Use with care -# Output - - - `Stage::EmulationProblem`: The Emulation model containing the model type, unbuilt JuMP model, Power - Systems system. - # Example +```julia template = ProblemTemplate(CopperPlatePowerModel, devices, branches, services) -problem = EmulationModel(MyOpProblemType template, system, optimizer) - -# Accepted Key Words - - - `initial_time::Dates.DateTime`: Initial Time for the model solve - - `warm_start::Bool` True will use the current Emulation point in the system to initialize variable values. False initializes all variables to zero. Default is true - - `export_pwl_vars::Bool` True will write the results of the piece-wise-linear intermediate variables. Slows down the simulation process significantly - - `allow_fails::Bool` True will allow the simulation to continue if the optimizer can't find a solution. Use with care, can lead to unwanted behaviour or results - - `optimizer_solve_log_print::Bool` Uses JuMP.unset_silent() to print the optimizer's log. By default all solvers are set to `MOI.Silent()` - - `name`: name of model, string or symbol; defaults to the type of template converted to a symbol +problem = EmulationModel(MyEmProblemType, template, system, optimizer) +``` """ function EmulationModel( ::Type{M}, @@ -181,8 +163,6 @@ function EmulationModel( end """ -EmulationModel(directory::AbstractString) - Construct an EmulationProblem from a serialized file. # Arguments @@ -433,8 +413,10 @@ keyword arguments to that function. # Examples +```julia status = run!(model; optimizer = GLPK.Optimizer, executions = 10) status = run!(model; output_dir = ./model_output, optimizer = GLPK.Optimizer, executions = 10) +``` """ function run!( model::EmulationModel{<:EmulationProblem}; @@ -505,10 +487,7 @@ Default solve method for an EmulationModel used inside of a Simulation. Solves p - `model::OperationModel`: operation model - `start_time::Dates.DateTime`: Initial Time of the simulation step in Simulation time. - `store::SimulationStore`: Simulation output store - -# Accepted Key Words - - - `exports`: realtime export of output. Use wisely, it can have negative impacts in the simulation times + - `exports = nothing`: realtime export of output. Use wisely, it can have negative impacts in the simulation times """ function solve!( step::Int, From 564fbf7541b8c660e175c8be1b931dab4cdb7627 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 21 Apr 2023 14:19:49 -0700 Subject: [PATCH 078/370] add simulation models --- docs/src/api/PowerSimulations.md | 31 +++++++++++- src/simulation/simulation.jl | 73 +++++++++++++++++++++------ src/simulation/simulation_models.jl | 26 ++++++++++ src/simulation/simulation_sequence.jl | 47 +++++++++++++++-- 4 files changed, 155 insertions(+), 22 deletions(-) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index ae3ca22203..c3710b63a8 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -13,6 +13,8 @@ end 1. [Device Models](#Device-Models) 2. [Decision Models](#Decision-Models) 3. [Emulation Models](#Emulation-Models) +4. [Simulation Models](#Simulation-Models) +5. [Variables](#Variables) # Device Models @@ -59,4 +61,31 @@ EmulationModel(::Type{M} where {M <: EmulationProblem}, ::ProblemTemplate, ::PSY EmulationModel(::AbstractString, ::MOI.OptimizerWithAttributes) build!(::EmulationModel) run!(::EmulationModel) -``` \ No newline at end of file +``` + +```@raw html +  +  +``` + +# Simulation Models + +Refer to the [Simulations Page](https://nrel-siip.github.io/PowerSimulations.jl/latest/modeler_guide/running_a_simulation/) to explanations on how to setup a Simulation, with Sequencing and Feedforwards. + +```@docs +SimulationModels +SimulationSequence +Simulation +Simulation(::AbstractString, ::Dict) +build!(::Simulation) +execute!(::Simulation) +``` + +```@raw html +  +  +``` + +# Variables + +## Common Variables \ No newline at end of file diff --git a/src/simulation/simulation.jl b/src/simulation/simulation.jl index 48545c84ce..4e49fa4012 100644 --- a/src/simulation/simulation.jl +++ b/src/simulation/simulation.jl @@ -1,12 +1,60 @@ """ Simulation( - steps::Int - models::SimulationModels, - sequence::Union{Nothing, SimulationSequence}, - simulation_folder::String, + sequence::SimulationSequence, name::String, - internal::Union{Nothing, SimulationInternal}, + steps::Int + models::SimulationModels, + simulation_folder::String, + initial_time::Union{Nothing, Dates.DateTime} ) + +Construct the Simulation structure to run the sequence of decision and emulation models specified. + +# Arguments + + -`sequence::SimulationSequence`: Simulation sequence that specify how the decision and emulation models will be executed. + -`name::String`: Name of the Simulation + -`steps::Int`: Number of steps on which the sequence of models will be executed + -`models::SimulationModels`: List of Decision and Emulation Models + -`simulation_folder::String`: Folder on which results will be stored + -`initial_time::Union{Nothing, Dates.DateTime} = nothing`: Initial time of which the simulation starts. If nothing it will default to the first timestamp + of time series of the system. + +# Example + +```julia +template_uc = template_unit_commitment() +template_ed = template_economic_dispatch() +my_decision_model_uc = DecisionModel(template_1, sys_uc, optimizer, name = "UC") +my_decision_model_ed = DecisionModel(template_ed, sys_ed, optimizer, name = "ED") +models = SimulationModels( + decision_models = [ + my_decision_model_uc, + my_decision_model_ed + ] +) +# The following sequence set the commitment variables (`OnVariable`) for `ThermalStandard` units from UC to ED. +sequence = SimulationSequence(; + models = models, + feedforwards = Dict( + "ED" => [ + SemiContinuousFeedforward(; + component_type = ThermalStandard, + source = OnVariable, + affected_values = [ActivePowerVariable], + ), + ], + ), +) + +sim = Simulation( + sequence = sequence, + name = "Sim", + steps = 5, + models = models, + simulation_folder = mktempdir(cleanup=true), +) +``` """ mutable struct Simulation steps::Int @@ -51,8 +99,6 @@ mutable struct Simulation end """ - Simulation(directory::AbstractString) - Constructs Simulation from a serialized directory. Callers should pass any kwargs here that they passed to the original Simulation. @@ -552,19 +598,15 @@ function _setup_simulation_partitions(sim::Simulation) end """ - build!(sim::Simulation) - -Build the Simulation, problems and the related folder structure +Build the Simulation, problems and the related folder structure. # Arguments - `sim::Simulation`: simulation object - - `serialize::Bool = true`: serializes the simulation objects in the simulation - `recorders::Vector{Symbol} = []`: recorder names to register + - `serialize::Bool = true`: serializes the simulation objects in the simulation - `console_level = Logging.Error`: - `file_level = Logging.Info`: - -Throws an exception if name is passed and the directory already exists. """ function build!( sim::Simulation; @@ -893,8 +935,6 @@ function _execute!( end """ - execute!(sim::Simulation; kwargs...) - Solves the simulation model for sequential Simulations. # Arguments @@ -905,9 +945,10 @@ The optional keyword argument `exports` controls exporting of results to CSV fil the simulation runs. Refer to [`export_results`](@ref) for a description of this argument. # Example - +```julia sim = Simulation("Test", 7, problems, "/Users/folder") execute!(sim::Simulation; kwargs...) +``` """ function execute!(sim::Simulation; kwargs...) file_mode = "a" diff --git a/src/simulation/simulation_models.jl b/src/simulation/simulation_models.jl index 1220cdaa8c..39b19f5115 100644 --- a/src/simulation/simulation_models.jl +++ b/src/simulation/simulation_models.jl @@ -1,7 +1,33 @@ """ + SimulationModels( + decision_models::Vector{<:DecisionModel}, + emulation_models::Union{Nothing, EmulationModel} + ) + Stores the OperationProblem definitions to be used in the simulation. When creating the SimulationModels, the order in which the models are created determines the order on which the simulation is executed. + +# Arguments + + - `decision_models::Vector{<:DecisionModel}`: Vector of decision models. + - `emulation_models::Union{Nothing, EmulationModel}`: Optional argument to include + an EmulationModel in the Simulation + +# Example + +```julia +template_uc = template_unit_commitment() +template_ed = template_economic_dispatch() +my_decision_model_uc = DecisionModel(template_1, sys_uc, optimizer, name = "UC") +my_decision_model_ed = DecisionModel(template_ed, sys_ed, optimizer, name = "ED") +models = SimulationModels( + decision_models = [ + my_decision_model_uc, + my_decision_model_ed + ] +) +``` """ mutable struct SimulationModels decision_models::Vector{<:DecisionModel} diff --git a/src/simulation/simulation_sequence.jl b/src/simulation/simulation_sequence.jl index 84079d3ad9..2ea134f7a9 100644 --- a/src/simulation/simulation_sequence.jl +++ b/src/simulation/simulation_sequence.jl @@ -192,12 +192,49 @@ function _attach_feedforwards(models::SimulationModels, feedforwards) return ff_dict end -@doc raw""" +""" SimulationSequence( - models::SimulationModels, - feedforward::Dict{Symbol, <:AbstractAffectFeedforward} - ini_cond_chronology::Dict{Symbol, <:FeedforwardChronology} - ) + models::SimulationModels, + feedforward::Dict{String, Vector{<:AbstractAffectFeedforward}} + ini_cond_chronology::InitialConditionChronology + ) + +Construct the simulation sequence between decision and emulation models. + +# Arguments + + - `models::SimulationModels`: Vector of decisions and emulation models. + - `feedforward = Dict{String, Vector{<:AbstractAffectFeedforward}}()`: Optional dictionary to specify how information + and variables are exchanged between decision and emulation models. + - `ini_cond_chronology::nitialConditionChronology = InterProblemChronology()`: TODO + +# Example + +```julia +template_uc = template_unit_commitment() +template_ed = template_economic_dispatch() +my_decision_model_uc = DecisionModel(template_1, sys_uc, optimizer, name = "UC") +my_decision_model_ed = DecisionModel(template_ed, sys_ed, optimizer, name = "ED") +models = SimulationModels( + decision_models = [ + my_decision_model_uc, + my_decision_model_ed + ] +) +# The following sequence set the commitment variables (`OnVariable`) for `ThermalStandard` units from UC to ED. +sequence = SimulationSequence(; + models = models, + feedforwards = Dict( + "ED" => [ + SemiContinuousFeedforward(; + component_type = ThermalStandard, + source = OnVariable, + affected_values = [ActivePowerVariable], + ), + ], + ), +) +``` """ mutable struct SimulationSequence horizons::OrderedDict{Symbol, Int} From 46aef7dfb6147870cdac5fa27b5212f188a2d491 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 21 Apr 2023 15:31:26 -0700 Subject: [PATCH 079/370] add variables and constraints --- docs/src/api/PowerSimulations.md | 186 ++++++++++++++++++++++++++++++- src/core/constraints.jl | 34 +++--- 2 files changed, 201 insertions(+), 19 deletions(-) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index c3710b63a8..85d8947475 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -15,7 +15,7 @@ end 3. [Emulation Models](#Emulation-Models) 4. [Simulation Models](#Simulation-Models) 5. [Variables](#Variables) - +6. [Constraints](#Constraints) # Device Models @@ -88,4 +88,186 @@ execute!(::Simulation) # Variables -## Common Variables \ No newline at end of file +For a list of variables for each device refer to its Formulations page. +### Common Variables + +```@docs +ActivePowerVariable +ReactivePowerVariable +PieceWiseLinearCostVariable +EnergyShortageVariable +EnergySurplusVariable +``` + +### Thermal Unit Variables + +```@docs +OnVariable +StartVariable +StopVariable +TimeDurationOn +TimeDurationOff +HotStartVariable +WarmStartVariable +ColdStartVariable +PowerAboveMinimumVariable +``` + +### Storage Unit Variables + +```@docs +ActivePowerOutVariable +ActivePowerInVariable +EnergyVariable +ReservationVariable +``` + +### Hydro Variables + +```@docs +WaterSpillageVariable +``` + +### Branches and Network Variables + +```@docs +FlowActivePowerVariable +FlowActivePowerFromToVariable +FlowActivePowerToFromVariable +FlowReactivePowerFromToVariable +FlowReactivePowerToFromVariable +PhaseShifterAngle +HVDCLosses +HVDCFlowDirectionVariable +VoltageMagnitude +VoltageAngle +``` + +### Regulation and Services Variables + +```@docs +ActivePowerReserveVariable +ServiceRequirementVariable +DeltaActivePowerUpVariable +DeltaActivePowerDownVariable +AdditionalDeltaActivePowerUpVariable +AdditionalDeltaActivePowerDownVariable +AreaMismatchVariable +SteadyStateFrequencyDeviation +SmoothACE +SystemBalanceSlackUp +SystemBalanceSlackDown +ReserveRequirementSlack +``` + + +```@raw html +  +  +``` + +# Constraints + +### Common Constraints + +```@docs +PieceWiseLinearCostConstraint + +``` + +### Network Constraints + +```@docs +ActiveConstraint +AreaDispatchBalanceConstraint +AreaParticipationAssignmentConstraint +BalanceAuxConstraint +CopperPlateBalanceConstraint +FrequencyResponseConstraint +NodalBalanceActiveConstraint +NodalBalanceReactiveConstraint +``` + +### Power Variable Limit Constraints + +```@docs +ActivePowerVariableLimitsConstraint +ReactivePowerVariableLimitsConstraint +ActivePowerVariableTimeSeriesLimitsConstraint +InputActivePowerVariableLimitsConstraint +OutputActivePowerVariableLimitsConstraint +``` + +### Regulation and Services Constraints + +```@docs +ParticipationAssignmentConstraint +RegulationLimitsConstraint +RequirementConstraint +ReserveEnergyCoverageConstraint +ReservePowerConstraint +``` + +### Thermal Unit Constraints + +```@docs +ActiveRangeICConstraint +CommitmentConstraint +DurationConstraint +MustRunConstraint +RampConstraint +RampLimitConstraint +StartupInitialConditionConstraint +StartupTimeLimitTemperatureConstraint +``` + +### Renewable Unit Constraints + +```@docs +EqualityConstraint + +``` + +### Hydro and Storage Constraints + +```@docs +EnergyBalanceConstraint +EnergyBudgetConstraint +EnergyCapacityConstraint +EnergyCapacityDownConstraint +EnergyCapacityUpConstraint +EnergyTargetConstraint +RangeLimitConstraint +``` + + +### Branches Constraints + +```@docs +AbsoluteValueConstraint +FlowLimitFromToConstraint +FlowLimitToFromConstraint +FlowRateConstraint +FlowRateConstraintFromTo +FlowRateConstraintToFrom +HVDCDirection +HVDCLossesAbsoluteValue +HVDCPowerBalance +NetworkFlowConstraint +RateLimitConstraint +RateLimitConstraintFromTo +RateLimitConstraintToFrom +PhaseAngleControlLimit +``` + +### Feedforward Constraints + +```@docs +FeedforwardSemiContinousConstraint +FeedforwardIntegralLimitConstraint +FeedforwardUpperBoundConstraint +FeedforwardLowerBoundConstraint +FeedforwardEnergyTargetConstraint +``` + + diff --git a/src/core/constraints.jl b/src/core/constraints.jl index a4e6d96243..14ddcf9ac4 100644 --- a/src/core/constraints.jl +++ b/src/core/constraints.jl @@ -27,7 +27,7 @@ Base.convert(::Type{ConstraintKey}, name::Symbol) = ConstraintKey(decode_symbol( struct AbsoluteValueConstraint <: ConstraintType end struct ActiveConstraint <: ConstraintType end -struct ActiveRangeConstraint <: ConstraintType end +struct ActiveRangeConstraint <: ConstraintType end #not being used struct ActiveRangeICConstraint <: ConstraintType end struct AreaDispatchBalanceConstraint <: ConstraintType end struct AreaParticipationAssignmentConstraint <: ConstraintType end @@ -40,33 +40,33 @@ struct EnergyBudgetConstraint <: ConstraintType end struct EnergyCapacityConstraint <: ConstraintType end struct EnergyCapacityDownConstraint <: ConstraintType end struct EnergyCapacityUpConstraint <: ConstraintType end -struct EnergyLimitConstraint <: ConstraintType end +struct EnergyLimitConstraint <: ConstraintType end # not being used struct EnergyTargetConstraint <: ConstraintType end -struct EnergyShortageVariableLimitsConstraint <: ConstraintType end +struct EnergyShortageVariableLimitsConstraint <: ConstraintType end # not being used struct EqualityConstraint <: ConstraintType end struct FeedforwardSemiContinousConstraint <: ConstraintType end struct FeedforwardIntegralLimitConstraint <: ConstraintType end struct FeedforwardUpperBoundConstraint <: ConstraintType end struct FeedforwardLowerBoundConstraint <: ConstraintType end struct FeedforwardEnergyTargetConstraint <: ConstraintType end -struct FlowActivePowerConstraint <: ConstraintType end -struct FlowActivePowerFromToConstraint <: ConstraintType end -struct FlowActivePowerToFromConstraint <: ConstraintType end -struct FlowLimitConstraint <: ConstraintType end +struct FlowActivePowerConstraint <: ConstraintType end #not being used +struct FlowActivePowerFromToConstraint <: ConstraintType end #not being used +struct FlowActivePowerToFromConstraint <: ConstraintType end #not being used +struct FlowLimitConstraint <: ConstraintType end #not being used struct FlowLimitFromToConstraint <: ConstraintType end struct FlowLimitToFromConstraint <: ConstraintType end struct FlowRateConstraint <: ConstraintType end struct FlowRateConstraintFromTo <: ConstraintType end struct FlowRateConstraintToFrom <: ConstraintType end -struct FlowReactivePowerConstraint <: ConstraintType end -struct FlowReactivePowerFromToConstraint <: ConstraintType end -struct FlowReactivePowerToFromConstraint <: ConstraintType end -struct HVDCPowerBalance <: ConstraintType end +struct FlowReactivePowerConstraint <: ConstraintType end #not being used +struct FlowReactivePowerFromToConstraint <: ConstraintType end #not being used +struct FlowReactivePowerToFromConstraint <: ConstraintType end #not being used +struct HVDCPowerBalance <: ConstraintType end struct FrequencyResponseConstraint <: ConstraintType end -struct InflowRangeConstraint <: ConstraintType end -struct InputPowerRangeConstraint <: ConstraintType end -struct InterConnectionLimitConstraint <: ConstraintType end -struct MustRunConstraint <: ConstraintType end +struct InflowRangeConstraint <: ConstraintType end #not being used +struct InputPowerRangeConstraint <: ConstraintType end #not being used +struct InterConnectionLimitConstraint <: ConstraintType end #not being used +struct MustRunConstraint <: ConstraintType end struct NetworkFlowConstraint <: ConstraintType end struct NodalBalanceActiveConstraint <: ConstraintType end struct NodalBalanceReactiveConstraint <: ConstraintType end @@ -82,8 +82,8 @@ struct RegulationLimitsConstraint <: ConstraintType end struct RequirementConstraint <: ConstraintType end struct ReserveEnergyCoverageConstraint <: ConstraintType end struct ReservePowerConstraint <: ConstraintType end -struct SACEPIDAreaConstraint <: ConstraintType end -struct StartTypeConstraint <: ConstraintType end +struct SACEPIDAreaConstraint <: ConstraintType end #not being used +struct StartTypeConstraint <: ConstraintType end #not being used struct StartupInitialConditionConstraint <: ConstraintType end struct StartupTimeLimitTemperatureConstraint <: ConstraintType end struct PhaseAngleControlLimit <: ConstraintType end From 41d56a1701d9334ee5e58fe739fb20143a59ede6 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 21 Apr 2023 15:47:04 -0700 Subject: [PATCH 080/370] add parameters --- docs/src/api/PowerSimulations.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index 85d8947475..11ad562422 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -16,6 +16,7 @@ end 4. [Simulation Models](#Simulation-Models) 5. [Variables](#Variables) 6. [Constraints](#Constraints) +7. [Parameters](#Parameters) # Device Models @@ -270,4 +271,33 @@ FeedforwardLowerBoundConstraint FeedforwardEnergyTargetConstraint ``` +# Parameters +### Time Series Parameters + +```@docs +ActivePowerTimeSeriesParameter +ReactivePowerTimeSeriesParameter +RequirementTimeSeriesParameter +EnergyTargetTimeSeriesParameter +EnergyBudgetTimeSeriesParameter +InflowTimeSeriesParameter +OutflowTimeSeriesParameter +``` + +### Variable Value Parameters + +```@docs +UpperBoundValueParameter +LowerBoundValueParameter +OnStatusParameter +EnergyLimitParameter +FixValueParameter +EnergyTargetParameter +``` + +### Objective Function Parameters + +```@docs +CostFunctionParameter +``` From 4e954172b3dd72a0d3470a932c04d1438378fb7d Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 21 Apr 2023 15:56:43 -0700 Subject: [PATCH 081/370] formatter --- src/core/constraints.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/constraints.jl b/src/core/constraints.jl index 14ddcf9ac4..79da9e177c 100644 --- a/src/core/constraints.jl +++ b/src/core/constraints.jl @@ -61,12 +61,12 @@ struct FlowRateConstraintToFrom <: ConstraintType end struct FlowReactivePowerConstraint <: ConstraintType end #not being used struct FlowReactivePowerFromToConstraint <: ConstraintType end #not being used struct FlowReactivePowerToFromConstraint <: ConstraintType end #not being used -struct HVDCPowerBalance <: ConstraintType end +struct HVDCPowerBalance <: ConstraintType end struct FrequencyResponseConstraint <: ConstraintType end struct InflowRangeConstraint <: ConstraintType end #not being used struct InputPowerRangeConstraint <: ConstraintType end #not being used struct InterConnectionLimitConstraint <: ConstraintType end #not being used -struct MustRunConstraint <: ConstraintType end +struct MustRunConstraint <: ConstraintType end struct NetworkFlowConstraint <: ConstraintType end struct NodalBalanceActiveConstraint <: ConstraintType end struct NodalBalanceReactiveConstraint <: ConstraintType end From da002a269eb28337edb4a00c5fc982dbfc2ffb40 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Mon, 24 Apr 2023 12:24:28 -0700 Subject: [PATCH 082/370] update common variables --- docs/src/api/PowerSimulations.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index 11ad562422..9e9c4b8d1a 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -96,8 +96,7 @@ For a list of variables for each device refer to its Formulations page. ActivePowerVariable ReactivePowerVariable PieceWiseLinearCostVariable -EnergyShortageVariable -EnergySurplusVariable + ``` ### Thermal Unit Variables @@ -117,9 +116,6 @@ PowerAboveMinimumVariable ### Storage Unit Variables ```@docs -ActivePowerOutVariable -ActivePowerInVariable -EnergyVariable ReservationVariable ``` @@ -127,6 +123,18 @@ ReservationVariable ```@docs WaterSpillageVariable +EnergyVariableUp +EnergyVariableDown +``` + +### Common for Hydro and Storage Variables + +```@docs +ActivePowerOutVariable +ActivePowerInVariable +EnergyVariable +EnergyShortageVariable +EnergySurplusVariable ``` ### Branches and Network Variables From 2e8e312843c64e98c18e1d7caf375ed510a848f6 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 1 May 2023 11:01:35 -0600 Subject: [PATCH 083/370] change logo --- docs/src/assets/logo.png | Bin 7406 -> 7972 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/src/assets/logo.png b/docs/src/assets/logo.png index c3a3349df3fb002567cb22c009d7c3398c90cf9d..c0c5d7d5949e7dfff418d3cd24bba209f785a49c 100644 GIT binary patch literal 7972 zcmX9@cQ~8h`wn8n7PGcAV%7+1R*fLhP(o2^$5z!EwMUE!EfSR2BdUt3Dq6H^l&Ddw zblB9aRkTLwFQ4!4k8{1(dERr~=eeKfyyrdVe()CNCTz@t%m4s@4TVHt000_pY6CMd zP%X2E$|BSUC=huw2moLK|JP{7W@7#V0HTv9guZoH;Z~8^9bwzh1sO!?5RudqQ&l1{!9UMN?s6VZU>9^h>%@qH7A=5g^1-7cgg zNWyRY-sB?IeoRq|~3SWShZ>2WMdL&p47(Hg`AzsNuCF_Zk?#;mXCT_w3 zaMXqMLk&gRPEMGZ0^Zuf9mPd~N_u*(uHd~zjjSu}2(RvOb(b#3qrnIar5(z}>OQeT zMAD1A0nw14ap={Tdb*?MAF?wxAvtLt9h`UL(Qe{w9{ft#GC&<*E1(*|2*(4U81LHF zkF=igT{NUb09b}s4JFG$9jzaarUl@$1zBThX-P-ojVk;WcJz>(@WJyiI?`(;747>- zPcL2D?f&@oHwqa2l2kfMPrPcurPAxbgZXP0&P$PUdNABUs(h&et${^WHs<7VG!Csq zromgBlyT%Z!r<3}xL9`eXtQHv-(l>D*kK$P0D9BXusOVN^;#Er=Wxh0U>T#H=ELk17ru*lF z(Lrc5JI_pWy*yW$o%1dQ!wKq~O3mh|%PCg=9Ax<>^j3!7ySs-xpuh zbGIR<-!ok0FKa?uc+=CD!$3w3W!?@d1Y^|{AP@cX{WJZI82fS$IN?Hp5s$sT{;_r6 z6|bgiFiwy(jq`e*#VaBRfe}6rrAVJju6?j=ZJPJH$elvg_`3)|fHOY@Zy1dlz&KHN zT?oQE>T4@}zeU+8Qmsrz;Uqoihj^o3v!(iT22j^g18LI%AVh}!F|t_*G1nf4hV0@u zHp8=X{)3k%D7AzNCc1!0iq^$HEHSX=WYrWz&`*eKOd}|(2l3U%{Rb9u>6fiI_-tX_ zxea;#YP|GY%-4ETNR*^DlWY70AVeo z04ci7br!;JSO{ELekUzSBWYm_8{2wt8>rf61|3v?+WLfs zB-$5^kROZg3~;r)$!bGmr~lkI&!z3@yar`GF~zL9^G@z9%W^w(@_IikLB2+@iPV#J zZ_ZlvhD&iD5WUk&kOHE!?7ai(h(u`*D;s8!5t1jyiqwy|WZXst1mv8V{^;!smuDWl zNGiSI>Su5a_k43HFGJ}<$_a!;TRU{8@u)vyjDW$pw9C!QWn2+mfBC+%KJD@P#Sy-N%|U-jxBBQDI$~r;2+aCccbkGx zhF{nwD{!;kIgqSHB7G&jFIlEn%O`7Be*|_5MdKmh6&MEpjI2A2(k8itRY*kXPAc|x zr2)-+KW1$NN~w`3!s^ND`JIpj#IJj5fA@QXU;Ns=`m50a<`GF-HD) z7n8pmZr|2e3E}qnVHA{a+`|QOoeG~p{t!Fq@qoC$92E4>i&{*jG8xgT=k*%&whw<;#{NiXE$wtr^k)s>A*8%&`f&=jK1w5Bz^q;sxOu%@V8@ z3Jn|M41!hn(XA5`kxcN>qPvie zP-;K3$6Trbi?c4*MWrPM@|hFxysV3`tXmluf#+liu&{xXw_9Zv1+MRm|3>XItTONy zQ`Vv8aQ!-j}bydHih39v|LM!x9qtIi{mzF8npu+8(bAxLZ%J=(nLLgQWtXiFu zZ(&&U9$~5N&lh;CorB0*j~O`E(#T86gFT_)YFG}!}VqR2|5TIOwEN3E<+ohl4ub| zUj!7~ILHPiYaA1DsqxkfEb}U5B2tOo6IUc~VnBh6@KJ(}QJ0x-`)2@vJ%T+1M*$iZ zvi4g+6AdZxSG~^OZOUaS&D;^!U5Y+VrE*LVJvu41h3~0xA=!12e@i%)rN9PtzynwW zJRbcr-iSCs4PYEvkK+k;6=1950g1fOo>5bv@a(?;CB%g>uy#E~gHDgY~pP9*Z zagsFPpZZzVL;k6)%Yv$7EeJ36zk0FiF&VQ0(a+XC)1;35NO{iA=ws8}J9;6=@4?!H zUT8+f&)=JoIy&oj6t)DB^ZL^QR6K-H%}?(t2%l zC*uyOWPi$OLXHZjf8rXQXH$GP;sW_IKPNg~b1BLv01gT^Wm1Ol=e# z`2X`UkzL5(J@$?Xcx43|D8G(LmAL?a3+eKS8EzrG(|W7&&ZvsxwpxcdLh<+M+UcQ$ zefVYXC%Heo5)Ptl;}7Y?xn94E*xLBvvDq+<9rF;*6q$DVw-6X%Sk&~EamD0uN{%VR z;J1_sGufd6KUtr)gj%mJCyh`Zmh*jNlX+|`cD$Xdj^ykx^K9&6BaM~(+|>(Dc8Xb- z?&QAPwdkWBRI=#qEq~|nc=`EDg-ImG5Lww;O~(rL;jsa$%%DB0=c&NfCkM;QM+=7& zKQ>L0f3Hz?MWc^?!AASl_8D!8*Oo%gysAvrjf=J7(V#)-Y$g}RV z$dx{ulNZUF#$K}PS!HGp^4ry9qg)HtWABb@t3^K@)vOrruZcN-FO7{{Rdzgj(AM7( zn8_z1$wfivk9pUx!kYTpIP9wvA863QgU07pi%eyk_a3TcEB`D>leSmmQUB?z?r(7K zJWfA2&uU=Q?8>b4i1JN3k~C7##7yV;)$+66cYd<#g>NKC4GjUttMVE9@mGLg)tuLR zqX!X?`U_-sB7S4n)NS^KG|J}wc3y_(9ZVwz727wM?x^$&`0)2gQZ3YAySgV3B{clW z@yz{nb{&7I@i}dFm3sl0g0OsN7Wi~OFm}ctv(&5FsA;AfQ3>uQVf=kQ=!*QzF{NEl zhWS#uV}i?{d^iPua~X5CBu>ZQzFmJaETnn(`vb+_)?=1oY?-F^b3uGgY~MNi6mwn& z{%-P8{pM_YYDSBl3mKB(KFE`%t%sUJiZlu)YONRji~g8OI+^)SNDy2;RfedSlw}^u z{CQf+Swmmf3L@gW0wbeu+1$TVkm1ra+*V24o($jcF4{ptlrbo~nBx_DpSehpcr;J4 zSIA-_cL2s=&UxRz=)S^Qjlgf(+Uv3n1Y_BTdC1Q>bbwI@K%B*%CBXqsy=`>+y3*qt z>lUMP>7##7hR<0q3XBGm!MRj;Wf9@xl~13{D>!Rdkg!zlrU2?@>UWwEsj$}Q>D`LK zSA^(V%ii_D1f9hLD#QcY`cxZ4^t!;W^YF@VtJ3vRZcG}yfmWraI4bRl8+k>ajFEa40 ziHf@GSZT^FhSHp~UBU2~$QmYfO`2q%(Vr}Rb-TCE-SDp^M>8Od;FL@g> zdq-ca>3r>NsUm*zxHKx!p!SzbUIj=$gX;%O&1@D=0fH|X2D58{{iY!aPKDn+{&Nuzxw4+Qfhl{U!AYz3tdP& zT2+Fg?>J5Ft=k{|UkE$sqi;43KR`+Hc{$C!S8eFhg9&yrh8(-9RUcnkYvc%_hUAxj z5ywe_m$QkMB`*bW@wL#T->Ysj-^ugm!!Wg$#=urzsq8zO?NeukQNgr*dC!=!O>{8TGdRv=k!6|NZ5-=DT~eaP24-O{VE+9Jax`n(icQ$ zD56I7aH+oS(evLC0hq>?;mD$-aena}yF_zIgG^YHc~>9lzErdKiAx48m?BJ#WLiB; zqYD29H8iUwwk%(mY9f1=IT0RE#KD~ZWujXlOUR=`pw;D$i=UXm_Kem}D4)6HkH)}h zrZFuso?=*UbGmQ5YkKmR@0;HrWZo}H8ozT57H_}mUYKNf*9rxEF@*=eGNyX{WOuRS zQEzAs>JsIqhH*_tPvD)RmXvX=9sN(%;Lgi=pDl5dDGcyYo?^(mwy8q)P(MtNHcOx2 zVje<+MJjkR>c8wem@pZM{FFi{)|_MYg+w?0+HMJOiBxbKKXQ8BUYaZC5KL}0tBBUV z@~NvKf8wPMOW)~g`9ITQm{a=|zB3v8s|gn{3B>$FIX1_a{5qB5q^T zoJ3;u>mU6bskx~Ayly{RZ!;>4ADVk(HfQ{wjk7h~v=CWOE^%H&TDqk;ousZ^#c`#o zzsylfx7Dc6xMjU=uMYjGYcDo#?e9Rf+DS%%$;U&6nuIEJ*x89SO3`%TI41hlrlh&Z zm-6a{+xts<4I*06PiNc;?r%m}=tg;D8F$o=?>lA#_IqTqJSgN_wK_uZJHho=(D}OW z@A=Fg?T;(sT@0Fs+y17ko-Ml6O&#xuaXdcT8l+#4uDK@|d~hg_x-CcG%@; zmj}r;hnc!aKc}j%L9`?+$CQ1Y^G0?*WLStH;0yhJNo>GuJWGjLzyEk!mV+uL*8DUw zGWb`HzLn5Bkp@s?QVI3t-=PGq_SmnZqiQKwT1dBwbkym}g7oM=E|GVq+Rt{j@;UCW zz2|&;dGvZ!y3P8;r)N)G#*#lx#iQYs?x1uB_;Gt)y%4$oX#e{qg3{)v=E3jx<+hxC zK`U!vVns1c8M6hV<_8yC^EHCB_!yU-B_P)7XP!6>Y}?}&8h#J0O!XQwtWmt_Z?vt7!8tO-EZ8v)`UAE0c;XYyCUaK*nSosmr9hT>c|_ zu+yQN?6c^9bU@Wn`0M7DAERGCg%|H-(F&?G-|hQ3(6a1$b~>SyU$Q&Z&E)AG)YpC% z_DQ?5Fw7&fH@P*bbG+wPicwlLELgttZdO0r;96WMI$);q{3M_XO(7!p{ib_&U;@kp zw`rh?hD9ZwjxN~$rK#Av(K+y-;`KUx*w=Z7I7tdHabY*D%{sS|BL6U1e$!oZ*VIG3 zGn10AGv^ikiAgbUtLRGWpS(MWj*icN^Cj~txF4){hQ6eC8qwdPdVYoFh20fa+Pi`G zAIYA!t?&^%w;m;lvq5=RGfkFVK*?8ILCM11WNF+Rv%aSc1hU!G@I$A5U|ezguf=8= zdhTusV34;vsJA_##^vW#t2x)Mo)sCXES?(RhWGSBukbV~1t4Eg(+R|6lT)bYtGcx&I zoagK#$+mggY~bss9^qwwSCeMM*KYrs(y{>TGXrd`kI=F^yZpcpzLy2MY)UKA-Voao zvTg1+v2esO_u?~#qHN{?3f<@BMK9 znRXprd+U#d>}zem7o_r14V7X-@($xct!f9b*{r`HMec>oE=OigL37EgHT6wBE?+nd zs?1%FKuoDj=I>Wx;5=D_nTU^B&XANH?Cz*xM~+J9~z{7~hC zUB>=XE&Z#k#XSY348@0FX7MaJ`gU<~;Mpsa`pZ~`J_%;UP7O)J7@YDgUs*_A-&xkd z830kv`A&B?2VaP9SiCQ0;cu=g`kJXn8*gXk9Z$bx`QYYO33=ya?){uXQ;GsN%{rMJ zD68odJ7F$%S^vv@QKYHT}YWcY)vzI7(dtoC7+TixnrO9_)|U-P(aA zh^xffK5Jxa&^#l<$tYT~O@Y*{&)PX%mMad9wj(MW=_TfXlC|hpZZFXg(gcLLTRZ8O z!fL+Ol30K~Jws(5)mef)t+2=y3T_&0$k zSI0IzI@(*oK9iS;Xsmpa&m!$ej;VoBX28+*b)UTR2eV|y4Y|`Fp9wkQX(!Vu`Dm&* zBxWudwg0rP86=S>m`0`{c%zrW##oX|zFlm@XVWfb2FR$Wxg^2MZwbn6AYtQNYYpa8 z>^m;~kDH9JGviE%t~5%DoA@R8EoBE6K>gBubW#s$C5T-_Z`m?cEChOv&=1zg zv1819Km(DH??`>=j8eo9@WN?(9)cNcU0iB8RB}mGI4c<=at<2lD<$2#g3h+4CGg}Q zzjC_e3n#cy)kaOQ^-QpY&??L?9!06fzJRU&&11L zx3Cs?U6K>EK)UXB_DHOH0O6$f%osQmn2>*V#C%np*tH)r5$)KWX$0>Klw!mwtR*0s zuWxh0#i3Yn+yT4b0zfhtl?_os_jQ~A<6Khca_f(~HaL@u4w$j5qp zWg?o26EW}Qa4NTlDAuqE9%l8%OCD#D0|xa}2HCj54QMDl7azzz{-J+KCvKW5b_)&< z5FexajbJY+Yq!>C7qc~QhgA{H1mln&J1e2;I?RUDANXNb;-0p38vU=f6IBEz>a{uX zJJciqUKV-=Jd*;==a|}w7b3$_=$P4Z*@jn+X@hd`N*OqRopua$2H9cH&({}?w&4Vp zIGjK0^#5$SLlyHIh$O5VFE;3rckANg{~X`*aH6-BGNmMbYio>t_TFkVRmQz;Y25%? zxrmv3togt0gNH!2$=!!25NcCy)3G{w~8;}jWD*6p7z2fzJrC`XSlVgn^NqMyEf1D^a92MI)Z5i*Cng|$^0gLFa$ zs~FO2_G zKQA5Wfqd_cIZ13>4B&y2>?mOe^1qE}G~Ev~cx<572Us^R&(QROX+EWBR`?1L3ch`6 zg2M=sEUcu*;olQnIgmo4lY`D}5yz%Cp9fcC-IP_d`-&P%YWDo~XpZd>m?KrUs%*Ff zkC(nypx~Q8>V+r??ld>{vBv=OF?<4}hc+b{|IBuRO+2r>g;cQBt(VxP3yyH2hJdjqe6(%+GV4{=}FPhUKS|Ne4BLL|@ z@3-ljxCql~nL~Lq3-PQtB;ywS&s>bGFVURef`6S23kD-AdGsJ$)RGWwH4hjGWynOK zv0BGEzOwd>kV`a~NLKNz#7u)No#9`jsghjCvK9skGX?63H4PWNbYj~5o%U9H=;1H7 zuZjqw9!v%jk`vAvpY39_A;GVljbfxg>HK{>MCreytNYK@kP;UFB;J+fI3rb*iXWsu4=LP^*vJ?v+sAh;0nlMgvB`)>@TQrx-xJSG5eOU|2bqHF?? zm&|Gp8l>0hY|RcbcHvF7Mz+WMiA5xV0Fww;RWfy6-A zgAlI7q|Z|g4^NCWl2W0)E A$^ZZW literal 7406 zcmXY0c|6nqA9oCM)mS5R3^h3uUsI%JQ6!?UFgc=Jo5|ctn475NXh=n2%sJ)=&5_6* z(~L|>C`WQsj^AfJet+z-_v3xMUeDL_`Fy|M`+SyQX>mbZL{@}{hezDh#OMm}P37U? z?Enh`EpHP>8}KDeFtPLJ;gQ$net5O7Jq_jIIgoE^WN00n^CS0ivNa~K(>L{k6#;P~ zIPIZF#e27^cy#-eIns)BOH{qSy30#y(Mn1!F73g!J=e8FlQUnNI&;jC{E`*o*Rqp4 z@Ba`?$W9PH#G2?7-$#U*Gj~g*C)UFVf7dA`8?!s7W+#`FLR{Fy*Yi8!^M4oXH}dL_ zn1XnQ>7k7wJDbm5D=BZMH5*UK@VHPX@fsrXPd?-=kAw1fAv5zozDmfqhsd`}cwLT9 z6n*Ju2=-e7R%{e)r^B&nNxx|5_`@%!j|!1Q1O3(l{SCn@!@v5ETWtxu*zkUz0+wI* z+)IL#gXQsu&emk+w7`n!@Hn$#4*?r89FEPuy%xBd44E$adEp2y>Yfdc%-j(3Rrlcs zG+{oNbi8!4Z8_Bq7$6uX?wea+?d4|(5bHx5l{er`g$7eIpX1gadastC=n{|qu(VH| z<*jO%nbB+w$D%T{JPiaG_n>=P@^5v9IhNq3s#UOgD8E8^Pm&0-+jy(XjdYFRN~E z4NOL3KN+at_wVxrW&-RmX8K828;s$1w!)<RcU|+t z(1?q_&Rsh=mT$igkjf4xKr$1As!yDTW1WSfxhc7YZM)J7DNr983_?9CR!3X~7=~Q} z07n4?FxH}D01$*QD3Ne_;)JJJ(8uS-&bmNVMfAnWId9`{lSqC>Kzt!EX&)oThG4`R z+CJV>E)`=ADWc;m#)d``xJF>g)Y>=b4T7a@-)ITkntKA5CBrTKez?{Hna#PG4GsXB zM)~R$q3G)sABRRB1WjJw*t(m`$FXlUG{Y#Va0_0&cCyfcRK(?}Y-)&^_yM7&A8sIt zq6_)~wI=idL@*CzSOEO!k>LaPG|zR|H6XyQQ5G;uzuu`5AXg#RBX`vDhSbsNNW)f@ z4=*~^9HB>2f;4~LP7RD9^uG7v;7I=|nck?#91mZtPLPo1O-I z_*~pw27(U>|HDcy;&Rx-DF&jmLAfd@y1)vz>PY}h-TpmXu|fgtY{sV7+u?`HO@{uTp1%TDb z`MjLP*oWo4DB8$90xZ6UE0+$Oy$=m|aEx>SFa^-C9zOtQ`{ob*qtW%M`JO@1%xh*C zp^-p7E7446pvA~V)!gd4;uMy9E$GtG63R-Cq<=@@C^u^^I-PNp#ocnRAh|XKO*1B_ zLRdS#a{3D3p?p>!T!kZvpPL8ji0@Q6`J~XBZ;ZreWaXDoM+_KHRz<1VMtYg)?giKJ zyb;X|2Bhm2*0TZI)5QP-fZYXzZRsF@6kg;rxI6|s{|~k#NEwUxe@hAb{1q{Yhin-I zQPt3OQgw!QL(>T|0OyuCGs$Fv@Y5l6K9a*jIH{+!kP@x$s|vZ;F$2hNNGszB<7j!$ zeT{Ul5UH3P{T7lz6@GrW1_P^wWddiH5b~KqP8nZa2L4cmFwDgh27W)J!|Q_v^)s1ae`!3mNa_-z^PfJ$$2>vUWcv0s5vQq_|Rh{h_g7=kyaTVwmUD?t2d(s&-A zW$nP9CZ*8^93%G#;wW2sBw!_HsF-2>bSxmNAx#Hl%F!|?bO3>wkS`=TOEb)@f=|?` zW47#paGYRCnW2fWZhi*!e$%QHL#L~*__T>L5ViKX!JnOj*}76Y<@#HH*CKwCTaGT9 zjHf~H4ZmQwja^qK?>9$W*wJv4urt~HSc|)?r+6Z0an$wpyk^3dVc~S_ytjZ5IW18K zI#1P@F^TWXKg)WgVTGnEya!HK)4@JTO83NKkvu8bd{H`EKge7DRKVEZu%9aIn!>-- z{#yhd8BT@-rTcT=vd)at{Ie_@1w8wgxTr%UGY-{PEza8^5%|`+jZLS&D~_nH@)~9t3>31 z^YGYKQo#}1$LGT;TBb5XJ^3B#L_E!Oe=TNpUm~MyN@WCaQHiUuq>)59Q^4&^#DP1z zeG=}ukBKOC52$rtLC@{J3R^!#&$+KF+dlhERYp6kOMNu{`<*{1;c9I!?R(_a9)0r2 z&Fbk+z$*2>lV&<6oz!&u{Gr~lHNvjx>6OAVN{+}QrPl0t`-c8G@kgC4yX)@={yAF$ z4=$9n`;NDrzftY4Z(Ygwf0OFJ9dJ zd1&w3mv=dn^zlPkHF~4ttu$2)W(KuE0p4a~W4~RwIbr*0W4yRmC{+)gS@H8L{znbPl0?-yb|tLEafWFp&G>kozU1d)#j(*rn+I7SIsc7r6aaZi6h@O4yMFx z(no$I``gN#T$#HWaibddHNs8YTRcGzmPs_j*h!3OUy@XXRi4^kDP1;vKDeTk@phc?dV_K)+gBi}H*qAbk7egnTer>?-5 zx6CjO5@}Jt^HOKKfx#Oky)W6CaT)cO75=h{>IabWqeags%Uy+_PD z8{^-l)Q!PTC&_z7)PFehZPm@a&I?bWMetbJut*mG#RrqxpUW*bU z{y6US9g|zgDmet0+JNH?H!9Mtr)~=@hPSp^e!G25^)@v?e3-+lj2AW~U z8|4>Ha*2t@77kc~cNVGa@F7TBN8 zc|pOaO*MRba~o|!%c-I7vg?#1tsl&G=OuTRE;YiA3;wWrNz|UMC-fiEhs*6(o3KCjQw$nIwvRoQ*)`uw$@Qqyujs?swMX`bKu z{_>w}hC$eOl(wTnQqH&-p;1}{?%Gx zm8+Qj-C}N!K6!ME-HQp3Mh3m#TV->cl#F>?TQ-Z!%s{H#yE3dd7Fv>v6BMs~mlPfHS3bE|i*V5DSQ=pj%)g ziH{EpI=A2Z$sX=*Js)CFE^ig`KFmudYAhbwU9TksC5Bg0=53|$7a@)`OP{C?!?5ND zxGBYX?GKW8a9Gextly&IUt>Db(EY8*xrxM{yG!_Ev)z2P!ZP}-R$2_1u};4Xp6xao zLmJM6jOZv}sX&~*$HvZ3Evaf`MR8)!ZD0kGV-dD|kS~=JHH&k;!7#V`QX_FIrC)fg z`1Hd4ovh{0**E__dOb9@>zUJB`_-N3WrxnjAZAx~7EPJ!r>}c$wG%tstAljY{oOZM z(PtHx_v6QWL@U<`Hl+qzZ?6mwn-LI>p24~E{cw`MJL6NnL6AvhZC+Vopl^$bhhmYP3g%2kZ1XfZ`rc54- zZ+n_2^dtL5nB(ngMcYwKN3PBT#nEKBcSB9s*ILab75pV(LCn93l%;VP@Q|l5DkK+X zRCm_fd^@DPHRJ7w)Ay@Fh4~>D}~5t@rFxUZ2-L z3o1}TNoVWMw?C(X7q{)n3WSE@%fkAoA)F7=! zRd2@~<<(jljZ$=MjabjTnhw)PyzL~WcIa?lJbW5IiR;RdQ4e(Uem0uCG;S%(# zeRhF7ZFmcHu4elgB-KG~dJ&T%i*%Mczt_xGVWM#Xr)UAbVLmgmIg$5vGC^hZEL-~d zAWJD$(cx~`1^87zPned}+6qMj{1uy>8q##7lzynUr$!vd{~HPt=^t*j=C2|Ll$NM>j_Q5ItoMt)2h=_KC5`*&Gr|RkI*hIFx=EZ;v?}`5J>=F&{B-^;Ya#db*A|ckwWdz=305%(HIZhk6Q>9I`UG?`(|so zupn}@737Bb(y!PbjuBl>r7AIe*&+g|6a|C6fUAx)VyW`q7vuf2D>rA$^|qHZS4xeu zSn_00@gtsMcg-pZCBWztRzI!T4xd7H5`Eo!Ukp7wRGZZJ{;pY5 zKG-<<^R zS^u)L&sErRiPv83Onl`FNx#BFC21Xy#Musp_cwuAQa!GxG`=^4udP z!9b-TMpbt@ohD|~`J{H=vqin*HffeP^b8RHOlwzI&}Aowu<~!`bJqGS^Hjq|b{_pu z5XDF%Hb<(g_h^ucVO`erBTJ0TZw9i-*8^8g#=8hdb=#eEkBs5~1gFry8LhG(MBG%= zNR(@_#T$z+XS;oZx;0)sUi(u@u!)Am-T72H1aL~GS%fSts`aGhscOG2MyyhpJtWE# z(l_4}`@=&$E+N2)gY--I)+T;qw%azn#9jw$qd*gOTeR11?{M>+{Pqf5xA-uNn2;Cw zc~*D0#7hNhbM!y5vszkl1(eE;_XljpZv5-N)_<57_Y-UPQSN#bL8n?~Ds8}rArm4| zJ?Goqr{Y$W@$5@|RgXKFmkJ(0bfE$ZTA7byU)XeA>q1VyKZ&{dTxKe9z$c1E^QeVk z!mkF*?EN~C$7zs$GzsH&Mf6x(n~IyAm3bsUv+WvJLdvKdD(APF7B$HRt!3ECsrSD zg&Ih~p5x^YA(=&6j^d9$8LPSm0%r=!gP9lOd?X>%TYOc*qx{(-q=l!Dk}@&3S<&#^ z6L9P<367n8r31&Nf?T0F0$MOI^EjJQHjH}7#|d=>61}Fz)?I7&gkOy$Y`=NUnj`?O zgJUBI(p2W>RR~q+3fc0HmomC3Q>`~_B2tL+C(@sW`+W$Z0mu3hq!vw`A}hCcZZ7NnCRd<58Aqy;JJY_|!B3q}1vj4J;} z0lxl9elSxaxx7;;TLsvG;!{%J10MahPbn6dtVub6##i_b?iwWM>gGR)ueb~OpP40424IS z!-`32x%2iz(G?7ep5gpoDyFYzIq-cG5W#>R{;Nuu8_VG27)Yk8D0QG42*;yHZVhx6 zA$be!iE@_aGNf-=C#=RT%sY!Xa43M>`VZ6BXL#tCAh)#BA8=?0R81Zmtx1=C8o;fl z7hTV)0-OP%+8qMtS)|8qo;&c!*$NRA zyumTs@u^WC;3d+6p*dYE%~5Ijz-S~v6-|h;Smv@-wuj~=7tT#dIcEw?sHD3O?t|b3 zz%0@+u3`@27tsj_F6Sfp3hbhPU6QVt&lkAh*gq|W-3PhOsyl7%gC=qVs`JW|A@1CO zJ%(=(MsnO~w=Fk=?<3QSogHo%ULh|F^`}a7WOOLxPfNu`naAsKqj#+QP<_EA2+s?~ zrhG!vCWJ{2VxOL$g3h1dzP9dIp7ZrZn5`OKpSKbM2ML0F(7(KELs0bU6;G&!LfQ;J zr>`^992Msy0$JR5dK?6*Qby5-SKOhHuA4j@i?^BP_l&c6N&390(d&>d5umFx&Kw0- z1(Wn;4kLLZOW_dwo;+&j1-L3NiJY41C7NW(2i85zWEjI$g-I078w5PfhKDhcvf!13 zvgHK_>1xCP4GA#jO*9a@2ux~(W{yZjmI^}f7ei;uR5=Q1BOu0|NHa3z`#-xKC)nV8 zkC?4WA9!tBfub*#cg7iO@{sAds#Vm9IcbKn`mMd;wlW z!?-`-;>0(PhCJa+naAP2l*4uVlKb*CLOqYh;X0x+Mr7$zLrK9M|UL!@U z8I(8){LomE*~!c2IbnkxerzSE#r`{!kVW!l0f0k}h;ZyH06cjKh0{;C!15A|=?EMj zpA2u5G}VQC4|SfjUxoTEl!7mR5{GlnaQkn|6Nw4MVm9M1uzC2KyjWj6q#B%gfa7@9d55>|e*V_V|o znIS}bq5~6wjrEv=mJldWR)v?q7wLl3&arnURHX<7dJ=T{&Rrj1# z*&;v{YVea7widUcc~Z148CWeUmcdXz<*}r|XBSK;qZ_LpIQF9Pm*XoPZz-PsiBV$O6b)_2`DLv9Fl%7prEm!C`XDedpJ@}i*C*K1h`d0qahk< zXi}Q=q8Ol`l=1e* zrom}RIA|u3e2bg;gg@#!T~A4(>t257S0Bd6rtZVS-?|0{l5oM1M6v_U;It52L>kyx zk-(E5zVGyPkXD6gA`DYr3wCps{_yWgN$uy0M_;6$0tgfPf-ajb0WgYPB0V8g8-RgX zDsCk5^^}PJwlN?rP1r@4ZZ+USXGA)Q{1NcBCRCDPgZKtdi$q%%(?!8<`C`_j#(0!q y_mm^O*xUoitYumBZ$NDysWBNPcu}6T88Oh5YK$KQHvxZO@|YT17*WyAQU3#$W#SqD From 01d2461536fe13c8d21b8e3f44ae29086ca05170 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 1 May 2023 11:03:54 -0600 Subject: [PATCH 084/370] sienna- siip rename --- .github/ISSUE_TEMPLATE/bug_report.md | 4 ++-- .github/ISSUE_TEMPLATE/feature_request.md | 2 +- README.md | 8 ++++---- docs/make.jl | 2 +- docs/src/api/PowerSimulations.md | 8 ++++---- docs/src/code_base_developer_guide/developer.md | 4 ++-- docs/src/formulation_library/RenewableGen.md | 2 +- docs/src/quick_start_guide.md | 2 +- src/simulation/simulation.jl | 6 +++--- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index bde7a38aa5..35211c5df7 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,7 +7,7 @@ assignees: '' --- -**If this is a question, something isn't working or an idea please start a Q&A discussion in the [Discussion tab](https://github.com/NREL-SIIP/PowerSimulations.jl/discussions)** +**If this is a question, something isn't working or an idea please start a Q&A discussion in the [Discussion tab](https://github.com/NREL-Sienna/PowerSimulations.jl/discussions)** Open a bug report only if you can provide the details below @@ -15,7 +15,7 @@ Open a bug report only if you can provide the details below A clear and concise description of what the bug is. **To Reproduce** -Steps to reproduce the behavior: +Steps to reproduce the behavior: Paste the code we can run to reproduce the error you are seeing **Expected behavior** diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 45533d0268..7055c5d792 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -7,7 +7,7 @@ assignees: '' --- -**If this is a question or an idea please start a Q&A discussion in the [Discussion tab](https://github.com/NREL-SIIP/PowerSimulations.jl/discussions)** +**If this is a question or an idea please start a Q&A discussion in the [Discussion tab](https://github.com/NREL-Sienna/PowerSimulations.jl/discussions)** **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I want to represent problem X [...] please be as specific as possible, including the mathematical formulations where appropriate. diff --git a/README.md b/README.md index 668bc44860..69a876f4e0 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # PowerSimulations.jl -[![Master - CI](https://github.com/NREL-SIIP/PowerSimulations.jl/actions/workflows/master-tests.yml/badge.svg)](https://github.com/NREL-SIIP/PowerSimulations.jl/actions/workflows/master-tests.yml) -[![codecov](https://codecov.io/gh/NREL-SIIP/PowerSimulations.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/NREL-SIIP/PowerSimulations.jl) -[![Documentation](https://github.com/NREL-SIIP/PowerSimulations.jl/workflows/Documentation/badge.svg)](https://nrel-siip.github.io/PowerSimulations.jl/latest) +[![Master - CI](https://github.com/NREL-Sienna/PowerSimulations.jl/actions/workflows/master-tests.yml/badge.svg)](https://github.com/NREL-Sienna/PowerSimulations.jl/actions/workflows/master-tests.yml) +[![codecov](https://codecov.io/gh/NREL-Sienna/PowerSimulations.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/NREL-Sienna/PowerSimulations.jl) +[![Documentation](https://github.com/NREL-Sienna/PowerSimulations.jl/workflows/Documentation/badge.svg)](https://nrel-siip.github.io/PowerSimulations.jl/latest) [![DOI](https://zenodo.org/badge/109443246.svg)](https://zenodo.org/badge/latestdoi/109443246) [](https://join.slack.com/t/nrel-siip/shared_invite/zt-glam9vdu-o8A9TwZTZqqNTKHa7q3BpQ) [![PowerSimulations Downloads](https://shields.io/endpoint?url=https://pkgs.genieframework.com/api/v1/badge/PowerSimulations)](https://pkgs.genieframework.com?packages=PowerSimulations) @@ -50,7 +50,7 @@ using PowerSystems ## Development -Contributions to the development and enhancement of PowerSimulations is welcome. Please see [CONTRIBUTING.md](https://github.com/NREL-SIIP/PowerSimulations.jl/blob/master/CONTRIBUTING.md) for code contribution guidelines. +Contributions to the development and enhancement of PowerSimulations is welcome. Please see [CONTRIBUTING.md](https://github.com/NREL-Sienna/PowerSimulations.jl/blob/master/CONTRIBUTING.md) for code contribution guidelines. ## License diff --git a/docs/make.jl b/docs/make.jl index 094f5f33d7..8fd65bd2e2 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -49,7 +49,7 @@ makedocs(; ) deploydocs(; - repo = "github.com/NREL-SIIP/PowerSimulations.jl.git", + repo = "github.com/NREL-Sienna/PowerSimulations.jl.git", target = "build", branch = "gh-pages", devbranch = "master", diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index 9e9c4b8d1a..2a906fa76f 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -43,7 +43,7 @@ Refer to the [Problem Templates Page](https://nrel-siip.github.io/PowerSimulatio ```@docs DecisionModel -DecisionModel(::Type{M} where {M <: DecisionProblem}, ::ProblemTemplate, ::PSY.System, ::Union{Nothing, JuMP.Model}) +DecisionModel(::Type{M} where {M <: DecisionProblem}, ::ProblemTemplate, ::PSY.System, ::Union{Nothing, JuMP.Model}) DecisionModel(::AbstractString, ::MOI.OptimizerWithAttributes) build!(::DecisionModel) solve!(::DecisionModel) @@ -200,7 +200,7 @@ NodalBalanceReactiveConstraint ### Power Variable Limit Constraints ```@docs -ActivePowerVariableLimitsConstraint +ActivePowerVariableLimitsConstraint ReactivePowerVariableLimitsConstraint ActivePowerVariableTimeSeriesLimitsConstraint InputActivePowerVariableLimitsConstraint @@ -244,7 +244,7 @@ EnergyBalanceConstraint EnergyBudgetConstraint EnergyCapacityConstraint EnergyCapacityDownConstraint -EnergyCapacityUpConstraint +EnergyCapacityUpConstraint EnergyTargetConstraint RangeLimitConstraint ``` @@ -266,7 +266,7 @@ NetworkFlowConstraint RateLimitConstraint RateLimitConstraintFromTo RateLimitConstraintToFrom -PhaseAngleControlLimit +PhaseAngleControlLimit ``` ### Feedforward Constraints diff --git a/docs/src/code_base_developer_guide/developer.md b/docs/src/code_base_developer_guide/developer.md index 7f820c0ced..5a278e1072 100644 --- a/docs/src/code_base_developer_guide/developer.md +++ b/docs/src/code_base_developer_guide/developer.md @@ -1,11 +1,11 @@ # Guidelines for Developers In order to contribute to `PowerSystems.jl` repository please read the following sections of -[`InfrastructureSystems.jl`](https://github.com/NREL-SIIP/InfrastructureSystems.jl) +[`InfrastructureSystems.jl`](https://github.com/NREL-Sienna/InfrastructureSystems.jl) documentation in detail: 1. [Style Guide](https://nrel-siip.github.io/InfrastructureSystems.jl/stable/style/) -2. [Contributing Guidelines](https://github.com/NREL-SIIP/PowerSystems.jl/blob/master/CONTRIBUTING.md) +2. [Contributing Guidelines](https://github.com/NREL-Sienna/PowerSystems.jl/blob/master/CONTRIBUTING.md) Pull requests are always welcome to fix bugs or add additional modeling capabilities. diff --git a/docs/src/formulation_library/RenewableGen.md b/docs/src/formulation_library/RenewableGen.md index 9852d434b7..fa40793634 100644 --- a/docs/src/formulation_library/RenewableGen.md +++ b/docs/src/formulation_library/RenewableGen.md @@ -127,4 +127,4 @@ Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance & Qg^\text{min} \le Qg_t \le Qg^\text{max} \\ & Qg_t = pf * Pg_t \end{aligned} -``` \ No newline at end of file +``` diff --git a/docs/src/quick_start_guide.md b/docs/src/quick_start_guide.md index 1661fb998d..6c2afcda2b 100644 --- a/docs/src/quick_start_guide.md +++ b/docs/src/quick_start_guide.md @@ -1,7 +1,7 @@ # Quick Start Guide * **Julia:** If this is your first time using Julia visit our [Introduction to Julia](https://nrel-siip.github.io/SIIP-Tutorial/fundamentals/introduction-to-julia/) and the official[Getting started with Julia](https://julialang.org/learning/). -* **Package Installation:** If you want to install packages check the [Package Manager](https://pkgdocs.julialang.org/v1/environments/) instructions, or you can refer to the [PowerSimulations installation instructions](@ref Installation). +* **Package Installation:** If you want to install packages check the [Package Manager](https://pkgdocs.julialang.org/v1/environments/) instructions, or you can refer to the [PowerSimulations installation instructions](@ref Installation). * **PowerSystems:** [PowerSystems.jl](https://github.com/nrel-siip/PowerSystems.jl) manages the data and is a fundamental dependency of PowerSimulations.jl. Check the [Understanding PowerSystems.jl page](https://nrel-siip.github.io/SIIP-Tutorial/how-to/understanding-powersystems-components/) and [PowerSystems.jl documentation](https://nrel-siip.github.io/PowerSystems.jl/stable/) to understand how the inputs to the models are organized. * **Dataset Library:** If you don't have a data set to start using `PowerSimulations.jl` check the test systems provided in [`PowerSystemCaseBuilder.jl`](https://nrel-siip.github.io/SIIP-Tutorial/how-to/power-system-case-builder/) diff --git a/src/simulation/simulation.jl b/src/simulation/simulation.jl index 4e49fa4012..1a142aa406 100644 --- a/src/simulation/simulation.jl +++ b/src/simulation/simulation.jl @@ -3,8 +3,8 @@ sequence::SimulationSequence, name::String, steps::Int - models::SimulationModels, - simulation_folder::String, + models::SimulationModels, + simulation_folder::String, initial_time::Union{Nothing, Dates.DateTime} ) @@ -910,7 +910,7 @@ function _execute!( # _apply_warm_start! can only be called once all the operations that read solutions # from the optimization container have been called. - # See https://github.com/NREL-SIIP/PowerSimulations.jl/pull/793#discussion_r761545526 + # See https://github.com/NREL-Sienna/PowerSimulations.jl/pull/793#discussion_r761545526 # for reference if warm_start_enabled(model) _apply_warm_start!(model) From 24e66091d2378848d2da4c1ed8c218411e3f9a16 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 1 May 2023 11:09:35 -0600 Subject: [PATCH 085/370] comment on constraint type --- src/core/device_model.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/device_model.jl b/src/core/device_model.jl index 6324a3d30f..11008d0a62 100644 --- a/src/core/device_model.jl +++ b/src/core/device_model.jl @@ -35,7 +35,7 @@ feedforward to enable passing values between operation model at simulation time - `::Type{B} where B<:AbstractDeviceFormulation`: Abstract Device Formulation - `feedforward::Array{<:AbstractAffectFeedforward} = Vector{AbstractAffectFeedforward}()` : use to pass parameters between models - `use_slacks::Bool = false` : Add slacks to the device model - - `duals::Vector{DataType} = Vector{DataType}()`: use to pass constraint type to calculate the duals + - `duals::Vector{DataType} = Vector{DataType}()`: use to pass constraint type to calculate the duals. The DataType needs to be a valid ConstraintType - `time_series_names::Dict{Type{<:TimeSeriesParameter}, String} = get_default_time_series_names(D, B)` : use to specify time series names associated to the device` - `attributes::Dict{String, Any} = get_default_attributes(D, B)` : use to specify attributes to the device From 0e0f3fb630d8e9b8c73b401048293ab9ebf58e14 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 1 May 2023 11:10:05 -0600 Subject: [PATCH 086/370] slacks clarification --- src/core/device_model.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/device_model.jl b/src/core/device_model.jl index 11008d0a62..af48590078 100644 --- a/src/core/device_model.jl +++ b/src/core/device_model.jl @@ -34,7 +34,7 @@ feedforward to enable passing values between operation model at simulation time - `::Type{D} where D<:PSY.Device`: Power System Device Type - `::Type{B} where B<:AbstractDeviceFormulation`: Abstract Device Formulation - `feedforward::Array{<:AbstractAffectFeedforward} = Vector{AbstractAffectFeedforward}()` : use to pass parameters between models - - `use_slacks::Bool = false` : Add slacks to the device model + - `use_slacks::Bool = false` : Add slacks to the device model. Implementation is model dependent and not all models feature slacks - `duals::Vector{DataType} = Vector{DataType}()`: use to pass constraint type to calculate the duals. The DataType needs to be a valid ConstraintType - `time_series_names::Dict{Type{<:TimeSeriesParameter}, String} = get_default_time_series_names(D, B)` : use to specify time series names associated to the device` - `attributes::Dict{String, Any} = get_default_attributes(D, B)` : use to specify attributes to the device From 42ccee7d3b64f611a39840e73ce9a29bee731d00 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 1 May 2023 11:10:56 -0600 Subject: [PATCH 087/370] pwl comment --- src/operation/decision_model.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index 120d8ef767..32c177332a 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -27,7 +27,7 @@ This builds the optimization problem of type M with the specific system and temp - `initialize_model::Bool = true`: Option to decide to initialize the model or not. - `initialization_file::String = ""`: TODO - `deserialize_initial_conditions::Bool = false`: Option to deserialize conditions - - `export_pwl_vars::Bool = false`: True to export all the pwl intermediate variables. It can slow down significantly the solve time. + - `export_pwl_vars::Bool = false`: True to export all the pwl intermediate variables. It can slow down significantly the build and solve time. - `allow_fails::Bool = false`: True to allow the simulation to continue even if the optimization step fails. Use with care. - `optimizer_solve_log_print::Bool = false`: Uses JuMP.unset_silent() to print the optimizer's log. By default all solvers are set to MOI.Silent() - `detailed_optimizer_stats::Bool = false`: True to save detailed optimizer stats log. @@ -43,7 +43,7 @@ This builds the optimization problem of type M with the specific system and temp ```julia template = ProblemTemplate(CopperPlatePowerModel, devices, branches, services) OpModel = DecisionModel(MockOperationProblem, template, system) -``` +``` """ mutable struct DecisionModel{M <: DecisionProblem} <: OperationModel name::Symbol @@ -263,7 +263,7 @@ Build the Decision Model based on the specified DecisionProblem. - `model::DecisionModel{<:DecisionProblem}`: DecisionModel object - `output_dir::String`: Output directory for results - `recorders::Vector{Symbol} = []`: recorder names to register - - `console_level = Logging.Error`: + - `console_level = Logging.Error`: - `file_level = Logging.Info`: - `disable_timer_outputs = false` : Enable/Disable timing outputs """ @@ -345,7 +345,7 @@ keyword arguments to that function. - `model::OperationModel = model`: operation model - `export_problem_results::Bool = false`: If true, export ProblemResults DataFrames to CSV files. - - `console_level = Logging.Error`: + - `console_level = Logging.Error`: - `file_level = Logging.Info`: - `disable_timer_outputs = false` : Enable/Disable timing outputs - `serialize::Bool = true`: If true, serialize the model to a file to allow re-execution later. From 7abe68172f357c2a4f6bb609b6c467eea4354927 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 1 May 2023 11:11:31 -0600 Subject: [PATCH 088/370] init --- src/operation/decision_model.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index 32c177332a..1886a43e78 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -25,7 +25,7 @@ This builds the optimization problem of type M with the specific system and temp - `warm_start::Bool = true`: True will use the current operation point in the system to initialize variable values. False initializes all variables to zero. Default is true - `system_to_file::Bool = true:`: True to create a copy of the system used in the model. - `initialize_model::Bool = true`: Option to decide to initialize the model or not. - - `initialization_file::String = ""`: TODO + - `initialization_file::String = ""`: This allows to pass pre-existing initialization values to avoid the solution of an optimization problem to find feasible initial conditions. - `deserialize_initial_conditions::Bool = false`: Option to deserialize conditions - `export_pwl_vars::Bool = false`: True to export all the pwl intermediate variables. It can slow down significantly the build and solve time. - `allow_fails::Bool = false`: True to allow the simulation to continue even if the optimization step fails. Use with care. From 893c1f4798bbfd3901457882d7a50ccc92ea04e8 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 1 May 2023 11:12:57 -0600 Subject: [PATCH 089/370] rebuild comment --- src/operation/decision_model.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index 1886a43e78..58d50380c4 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -33,8 +33,8 @@ This builds the optimization problem of type M with the specific system and temp - `detailed_optimizer_stats::Bool = false`: True to save detailed optimizer stats log. - `calculate_conflict::Bool = false`: True to use solver to calculate conflicts for infeasible problems. Only specific solvers are able to calculate conflicts. - `direct_mode_optimizer::Bool = false`: True to use the solver in direct mode. Creates a [JuMP.direct_model](https://jump.dev/JuMP.jl/dev/reference/models/#JuMP.direct_model). - - `store_variable_names::Bool = false`: True to store variable names in optimization model. - - `rebuild_model::Bool = false`: TODO + - `store_variable_names::Bool = false`: to store variable names in optimization model. Decreases the build times. + - `rebuild_model::Bool = false`: It will force the rebuild of the underlying JuMP model with each call to update the model. It increases solution times, use only if the model can't be updated in memory. - `initial_time::Dates.DateTime = UNSET_INI_TIME`: Initial Time for the model solve. - `time_series_cache_size::Int = IS.TIME_SERIES_CACHE_SIZE_BYTES`: Size in bytes to cache for each time array. Default is 1 MiB. Set to 0 to disable. From aa8e043a4a1524abf638c3ee53c7441dca4ceadd Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 1 May 2023 11:15:34 -0600 Subject: [PATCH 090/370] more docstring changes --- src/operation/decision_model.jl | 2 +- src/operation/emulation_model.jl | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index 58d50380c4..8222106b1d 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -344,7 +344,7 @@ keyword arguments to that function. # Arguments - `model::OperationModel = model`: operation model - - `export_problem_results::Bool = false`: If true, export ProblemResults DataFrames to CSV files. + - `export_problem_results::Bool = false`: If true, export ProblemResults DataFrames to CSV files. Reduces solution times during simulation. - `console_level = Logging.Error`: - `file_level = Logging.Info`: - `disable_timer_outputs = false` : Enable/Disable timing outputs diff --git a/src/operation/emulation_model.jl b/src/operation/emulation_model.jl index b55aef670b..4622a6fc7b 100644 --- a/src/operation/emulation_model.jl +++ b/src/operation/emulation_model.jl @@ -24,19 +24,19 @@ This builds the optimization problem of type M with the specific system and temp - `warm_start::Bool = true`: True will use the current operation point in the system to initialize variable values. False initializes all variables to zero. Default is true - `system_to_file::Bool = true:`: True to create a copy of the system used in the model. - `initialize_model::Bool = true`: Option to decide to initialize the model or not. - - `initialization_file::String = ""`: TODO + - `initialization_file::String = ""`: This allows to pass pre-existing initialization values to avoid the solution of an optimization problem to find feasible initial conditions. - `deserialize_initial_conditions::Bool = false`: Option to deserialize conditions - - `export_pwl_vars::Bool = false`: True to export all the pwl intermediate variables. It can slow down significantly the solve time. + - `export_pwl_vars::Bool = false`: True to export all the pwl intermediate variables. It can slow down significantly the build and solve time. - `allow_fails::Bool = false`: True to allow the simulation to continue even if the optimization step fails. Use with care. - `calculate_conflict::Bool = false`: True to use solver to calculate conflicts for infeasible problems. Only specific solvers are able to calculate conflicts. - `optimizer_solve_log_print::Bool = false`: Uses JuMP.unset_silent() to print the optimizer's log. By default all solvers are set to MOI.Silent() - `detailed_optimizer_stats::Bool = false`: True to save detailed optimizer stats log. - `direct_mode_optimizer::Bool = false`: True to use the solver in direct mode. Creates a [JuMP.direct_model](https://jump.dev/JuMP.jl/dev/reference/models/#JuMP.direct_model). - `store_variable_names::Bool = false`: True to store variable names in optimization model. - - `rebuild_model::Bool = false`: TODO + - `rebuild_model::Bool = false`: It will force the rebuild of the underlying JuMP model with each call to update the model. It increases solution times, use only if the model can't be updated in memory. - `initial_time::Dates.DateTime = UNSET_INI_TIME`: Initial Time for the model solve. - `time_series_cache_size::Int = IS.TIME_SERIES_CACHE_SIZE_BYTES`: Size in bytes to cache for each time array. Default is 1 MiB. Set to 0 to disable. - + # Example ```julia From 3062da672d565909b06b954dd9304e75bc54505f Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 1 May 2023 11:19:38 -0600 Subject: [PATCH 091/370] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 69a876f4e0..74567b9d9b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Master - CI](https://github.com/NREL-Sienna/PowerSimulations.jl/actions/workflows/master-tests.yml/badge.svg)](https://github.com/NREL-Sienna/PowerSimulations.jl/actions/workflows/master-tests.yml) [![codecov](https://codecov.io/gh/NREL-Sienna/PowerSimulations.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/NREL-Sienna/PowerSimulations.jl) -[![Documentation](https://github.com/NREL-Sienna/PowerSimulations.jl/workflows/Documentation/badge.svg)](https://nrel-siip.github.io/PowerSimulations.jl/latest) +[![Documentation](https://github.com/NREL-Sienna/PowerSimulations.jl/workflows/Documentation/badge.svg)](https://nrel-sienna.github.io/PowerSimulations.jl/latest) [![DOI](https://zenodo.org/badge/109443246.svg)](https://zenodo.org/badge/latestdoi/109443246) [](https://join.slack.com/t/nrel-siip/shared_invite/zt-glam9vdu-o8A9TwZTZqqNTKHa7q3BpQ) [![PowerSimulations Downloads](https://shields.io/endpoint?url=https://pkgs.genieframework.com/api/v1/badge/PowerSimulations)](https://pkgs.genieframework.com?packages=PowerSimulations) From ca2070c412285da90bf577aa838186db5d7f43e3 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 24 Apr 2023 12:20:16 -0600 Subject: [PATCH 092/370] remove storage from base code --- docs/src/formulation_library/Storage.md | 220 ------- src/PowerSimulations.jl | 7 - src/core/formulations.jl | 20 - .../storage_constructor.jl | 585 ------------------ src/devices_models/devices/storage.jl | 401 ------------ test/test_device_storage_constructors.jl | 314 ---------- test/test_model_decision.jl | 29 - test/test_model_emulation.jl | 74 --- 8 files changed, 1650 deletions(-) delete mode 100644 docs/src/formulation_library/Storage.md delete mode 100644 src/devices_models/device_constructors/storage_constructor.jl delete mode 100644 src/devices_models/devices/storage.jl delete mode 100644 test/test_device_storage_constructors.jl diff --git a/docs/src/formulation_library/Storage.md b/docs/src/formulation_library/Storage.md deleted file mode 100644 index 52ad9264b4..0000000000 --- a/docs/src/formulation_library/Storage.md +++ /dev/null @@ -1,220 +0,0 @@ -# `PowerSystems.Storage` Formulations - -Valid `DeviceModel`s for subtypes of `Storage` include the following: - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.generate_device_formulation_combinations() -filter!(x -> x["device_type"] <: Storage, combos) -combo_table = DataFrame( - "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], - "Device Type" => ["[$(c["device_type"])](https://nrel-siip.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], - "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], - ) -mdtable(combo_table, latex = false) -``` - ---- - -## `BookKeeping` - -```@docs -BookKeeping -``` - -**Variables:** - -- [`ActivePowerInVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `-1 * PowerSystems.get_active_power(device)` -- [`ActivePowerOutVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`EnergyVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device)` -- [`ReservationVariable`](@ref): - - only included if `DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage; attributes = Dict(reservation => true))` - - Bounds: {0, 1} - - Default initial value: 1 - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` -- ``E^\text{max}`` = `PowerSystems.get_storage_capacity(device)` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg_t``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& E_{t+1} = E_t + (Pg^{in}_t - Pg^{out}_t) \cdot \Delta T \\ -& Pg^{in}_t - r * Pg^\text{in, max} \le Pg^\text{in, max} \\ -& Pg^{out}_t + r * Pg^\text{out, max} \le Pg^\text{out, max} \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} \\ -& E_t \le E^\text{max} -\end{aligned} -``` - ---- - -## `EnergyTarget` - -```@docs -EnergyTarget -``` - -**Variables:** - -- [`ActivePowerInVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `-1 * PowerSystems.get_active_power(device)` -- [`ActivePowerOutVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`EnergyVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device)` -- [`EnergyShortageVariable`](@ref): - - Bounds: [ , 0.0] - - Default initial value: 0.0 -- [`EnergySurplusVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`ReservationVariable`](@ref): - - only included if `DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage; attributes = Dict(reservation => true))` - - Bounds: {0, 1} - - Default initial value: 1 - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` -- ``E^\text{max}`` = `PowerSystems.get_storage_capacity(device)` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(Storage, EnergyTarget) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg_t``, -and objective function terms for [StorageManagementCost](@ref). - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& E_{t+1} = E_t + (Pg^{in}_t - Pg^{out}_t) \cdot \Delta T \\ -& E_t - E^{surplus}_t + E^{shortage}_t = EnergyTargetTimeSeriesParameter_t \\ -& Pg^{in}_t - r * Pg^\text{in, max} \le Pg^\text{in, max} \\ -& Pg^{out}_t + r * Pg^\text{out, max} \le Pg^\text{out, max} \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max}\\ -& E_t \le E^\text{max} -\end{aligned} -``` - ---- - -## `BatteryAncillaryServices` - -```@docs -BatteryAncillaryServices -``` - -**Variables:** - -- [`ActivePowerInVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `-1 * PowerSystems.get_active_power(device)` -- [`ActivePowerOutVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`EnergyVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device)` -- [`ReservationVariable`](@ref): - - only included if `DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage; attributes = Dict(reservation => true))` - - Bounds: {0, 1} - - Default initial value: 1 - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` -- ``E^\text{max}`` = `PowerSystems.get_storage_capacity(device)` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(Storage, EnergyTarget) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg_t``, -and objective function terms for [StorageManagementCost](@ref). - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& E_{t+1} = E_t + (Pg^{in}_t - Pg^{out}_t) \cdot \Delta T \\ -& E_t - E^{surplus}_t + E^{shortage}_t = EnergyTargetTimeSeriesParameter_t \\ -& Pg^{in}_t - r * Pg^\text{in, max} \le Pg^\text{in, max} \\ -& Pg^{out}_t + r * Pg^\text{out, max} \le Pg^\text{out, max} \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max}\\ -& E_t \le E^\text{max} -\end{aligned} -``` diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 4594615521..51f5c64e42 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -60,11 +60,6 @@ export HydroCommitmentReservoirBudget export HydroCommitmentReservoirStorage export HydroDispatchPumpedStorage -######## Renewable Formulations ######## -export BookKeeping -export BatteryAncillaryServices -export EnergyTarget - ######## Thermal Formulations ######## export ThermalStandardUnitCommitment export ThermalBasicUnitCommitment @@ -535,7 +530,6 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") -include("devices_models/devices/storage.jl") include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") @@ -562,7 +556,6 @@ include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") -include("devices_models/device_constructors/storage_constructor.jl") include("devices_models/device_constructors/regulationdevice_constructor.jl") # Network constructors diff --git a/src/core/formulations.jl b/src/core/formulations.jl index daa300da11..dedffc553a 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -132,26 +132,6 @@ Formulation type to add real and reactive injection variables with constant powe """ struct RenewableConstantPowerFactor <: AbstractRenewableDispatchFormulation end -############################ Storage Generation Formulations ############################### -abstract type AbstractStorageFormulation <: AbstractDeviceFormulation end -abstract type AbstractEnergyManagement <: AbstractStorageFormulation end - -""" -Formulation type to add basic storage formulation. With `attributes=Dict("reservation"=>true)` the formulation is augmented -with abinary variable to prevent simultanious charging and discharging -""" -struct BookKeeping <: AbstractStorageFormulation end -""" -Formulation type to add storage formulation than can provide ancillary services. With `attributes=Dict("reservation"=>true)` the formulation is augmented -with abinary variable to prevent simultanious charging and discharging -""" -struct BatteryAncillaryServices <: AbstractStorageFormulation end -""" -Formulation type to add storage formulation that respects end of horizon energy state of charge target. With `attributes=Dict("reservation"=>true)` the formulation is augmented -with abinary variable to prevent simultanious charging and discharging -""" -struct EnergyTarget <: AbstractEnergyManagement end - """ Abstract type for Branch Formulations (a.k.a Models) diff --git a/src/devices_models/device_constructors/storage_constructor.jl b/src/devices_models/device_constructors/storage_constructor.jl deleted file mode 100644 index 721435ab28..0000000000 --- a/src/devices_models/device_constructors/storage_constructor.jl +++ /dev/null @@ -1,585 +0,0 @@ -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{St, D}, - network_model::NetworkModel{S}, -) where {St <: PSY.Storage, D <: AbstractStorageFormulation, S <: PM.AbstractPowerModel} - devices = get_available_components(St, sys) - - add_variables!(container, ActivePowerInVariable, devices, D()) - add_variables!(container, ActivePowerOutVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, EnergyVariable, devices, D()) - if get_attribute(model, "reservation") - add_variables!(container, ReservationVariable, devices, D()) - end - - initial_conditions!(container, devices, D()) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerInVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{St, D}, - network_model::NetworkModel{S}, -) where {St <: PSY.Storage, D <: AbstractStorageFormulation, S <: PM.AbstractPowerModel} - devices = get_available_components(St, sys) - - add_constraints!( - container, - OutputActivePowerVariableLimitsConstraint, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - InputActivePowerVariableLimitsConstraint, - ActivePowerInVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - EnergyCapacityConstraint, - EnergyVariable, - devices, - model, - network_model, - ) - - # Energy Balanace limits - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - - add_constraint_dual!(container, sys, model) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{St, D}, - network_model::NetworkModel{S}, -) where { - St <: PSY.Storage, - D <: AbstractStorageFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = get_available_components(St, sys) - - add_variables!(container, ActivePowerInVariable, devices, D()) - add_variables!(container, ActivePowerOutVariable, devices, D()) - add_variables!(container, EnergyVariable, devices, D()) - if get_attribute(model, "reservation") - add_variables!(container, ReservationVariable, devices, D()) - end - - initial_conditions!(container, devices, D()) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerInVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{St, D}, - network_model::NetworkModel{S}, -) where { - St <: PSY.Storage, - D <: AbstractStorageFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = get_available_components(St, sys) - - add_constraints!( - container, - OutputActivePowerVariableLimitsConstraint, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - InputActivePowerVariableLimitsConstraint, - ActivePowerInVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - EnergyCapacityConstraint, - EnergyVariable, - devices, - model, - network_model, - ) - - # Energy Balanace limits - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - add_constraint_dual!(container, sys, model) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{St, EnergyTarget}, - network_model::NetworkModel{S}, -) where {St <: PSY.Storage, S <: PM.AbstractPowerModel} - devices = get_available_components(St, sys) - - add_variables!(container, ActivePowerInVariable, devices, EnergyTarget()) - add_variables!(container, ActivePowerOutVariable, devices, EnergyTarget()) - add_variables!(container, ReactivePowerVariable, devices, EnergyTarget()) - add_variables!(container, EnergyVariable, devices, EnergyTarget()) - add_variables!(container, EnergyShortageVariable, devices, EnergyTarget()) - add_variables!(container, EnergySurplusVariable, devices, EnergyTarget()) - if get_attribute(model, "reservation") - add_variables!(container, ReservationVariable, devices, EnergyTarget()) - end - - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - - initial_conditions!(container, devices, EnergyTarget()) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerInVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{St, EnergyTarget}, - network_model::NetworkModel{S}, -) where {St <: PSY.Storage, S <: PM.AbstractPowerModel} - devices = get_available_components(St, sys) - - add_constraints!( - container, - OutputActivePowerVariableLimitsConstraint, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - InputActivePowerVariableLimitsConstraint, - ActivePowerInVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - EnergyCapacityConstraint, - EnergyVariable, - devices, - model, - network_model, - ) - - # Energy Balanace limits - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{St, EnergyTarget}, - network_model::NetworkModel{S}, -) where {St <: PSY.Storage, S <: PM.AbstractActivePowerModel} - devices = get_available_components(St, sys) - - add_variables!(container, ActivePowerInVariable, devices, EnergyTarget()) - add_variables!(container, ActivePowerOutVariable, devices, EnergyTarget()) - add_variables!(container, EnergyVariable, devices, EnergyTarget()) - add_variables!(container, EnergyShortageVariable, devices, EnergyTarget()) - add_variables!(container, EnergySurplusVariable, devices, EnergyTarget()) - if get_attribute(model, "reservation") - add_variables!(container, ReservationVariable, devices, EnergyTarget()) - end - - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - - initial_conditions!(container, devices, EnergyTarget()) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerInVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{St, EnergyTarget}, - network_model::NetworkModel{S}, -) where {St <: PSY.Storage, S <: PM.AbstractActivePowerModel} - devices = get_available_components(St, sys) - - add_constraints!( - container, - OutputActivePowerVariableLimitsConstraint, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - InputActivePowerVariableLimitsConstraint, - ActivePowerInVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - EnergyCapacityConstraint, - EnergyVariable, - devices, - model, - network_model, - ) - - # Energy Balanace limits - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{St, BatteryAncillaryServices}, - network_model::NetworkModel{S}, -) where {St <: PSY.Storage, S <: PM.AbstractPowerModel} - devices = get_available_components(St, sys) - - add_variables!(container, ActivePowerInVariable, devices, BatteryAncillaryServices()) - add_variables!(container, ActivePowerOutVariable, devices, BatteryAncillaryServices()) - add_variables!(container, ReactivePowerVariable, devices, BatteryAncillaryServices()) - add_variables!(container, EnergyVariable, devices, BatteryAncillaryServices()) - if get_attribute(model, "reservation") - add_variables!(container, ReservationVariable, devices, BatteryAncillaryServices()) - end - - initial_conditions!(container, devices, BatteryAncillaryServices()) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerInVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - if has_service_model(model) - add_expressions!(container, ReserveRangeExpressionLB, devices, model) - add_expressions!(container, ReserveRangeExpressionUB, devices, model) - end - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{St, BatteryAncillaryServices}, - network_model::NetworkModel{S}, -) where {St <: PSY.Storage, S <: PM.AbstractPowerModel} - devices = get_available_components(St, sys) - - add_constraints!( - container, - OutputActivePowerVariableLimitsConstraint, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - InputActivePowerVariableLimitsConstraint, - ActivePowerInVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - EnergyCapacityConstraint, - EnergyVariable, - devices, - model, - network_model, - ) - - # Energy Balanace limits - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - if has_service_model(model) - add_constraints!( - container, - ReserveEnergyCoverageConstraint, - devices, - model, - network_model, - ) - add_constraints!(container, RangeLimitConstraint, devices, model, network_model) - end - add_feedforward_constraints!(container, model, devices) - - add_constraint_dual!(container, sys, model) - - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{St, BatteryAncillaryServices}, - network_model::NetworkModel{S}, -) where {St <: PSY.Storage, S <: PM.AbstractActivePowerModel} - devices = get_available_components(St, sys) - - add_variables!(container, ActivePowerInVariable, devices, BatteryAncillaryServices()) - add_variables!(container, ActivePowerOutVariable, devices, BatteryAncillaryServices()) - add_variables!(container, EnergyVariable, devices, BatteryAncillaryServices()) - if get_attribute(model, "reservation") - add_variables!(container, ReservationVariable, devices, BatteryAncillaryServices()) - end - - initial_conditions!(container, devices, BatteryAncillaryServices()) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerInVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - if has_service_model(model) - add_expressions!(container, ReserveRangeExpressionLB, devices, model) - add_expressions!(container, ReserveRangeExpressionUB, devices, model) - end - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{St, BatteryAncillaryServices}, - network_model::NetworkModel{S}, -) where {St <: PSY.Storage, S <: PM.AbstractActivePowerModel} - devices = get_available_components(St, sys) - - add_constraints!( - container, - OutputActivePowerVariableLimitsConstraint, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - InputActivePowerVariableLimitsConstraint, - ActivePowerInVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - EnergyCapacityConstraint, - EnergyVariable, - devices, - model, - network_model, - ) - - # Energy Balanace limits - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - if has_service_model(model) - add_constraints!( - container, - ReserveEnergyCoverageConstraint, - devices, - model, - network_model, - ) - add_constraints!(container, RangeLimitConstraint, devices, model, network_model) - end - - add_feedforward_constraints!(container, model, devices) - - add_constraint_dual!(container, sys, model) - - return -end diff --git a/src/devices_models/devices/storage.jl b/src/devices_models/devices/storage.jl deleted file mode 100644 index 4be21a81bd..0000000000 --- a/src/devices_models/devices/storage.jl +++ /dev/null @@ -1,401 +0,0 @@ -#! format: off -requires_initialization(::AbstractStorageFormulation) = false - -get_variable_multiplier(_, ::Type{<:PSY.Storage}, ::AbstractStorageFormulation) = NaN -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.Storage}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ReserveRangeExpressionUB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.Storage}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ReserveRangeExpressionLB -########################### ActivePowerInVariable, Storage ################################# -get_variable_binary(::ActivePowerInVariable, ::Type{<:PSY.Storage}, ::AbstractStorageFormulation) = false -get_variable_lower_bound(::ActivePowerInVariable, d::PSY.Storage, ::AbstractStorageFormulation) = 0.0 -get_variable_upper_bound(::ActivePowerInVariable, d::PSY.Storage, ::AbstractStorageFormulation) = PSY.get_input_active_power_limits(d).max -get_variable_multiplier(::ActivePowerInVariable, d::Type{<:PSY.Storage}, ::AbstractStorageFormulation) = -1.0 - -########################### ActivePowerOutVariable, Storage ################################# -get_variable_binary(::ActivePowerOutVariable, ::Type{<:PSY.Storage}, ::AbstractStorageFormulation) = false -get_variable_lower_bound(::ActivePowerOutVariable, d::PSY.Storage, ::AbstractStorageFormulation) = 0.0 -get_variable_upper_bound(::ActivePowerOutVariable, d::PSY.Storage, ::AbstractStorageFormulation) = PSY.get_output_active_power_limits(d).max -get_variable_multiplier(::ActivePowerOutVariable, d::Type{<:PSY.Storage}, ::AbstractStorageFormulation) = 1.0 - -############## ReactivePowerVariable, Storage #################### -get_variable_multiplier(::ReactivePowerVariable, ::Type{<:PSY.Storage}, ::AbstractStorageFormulation) = 1.0 -get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.Storage}, ::AbstractStorageFormulation) = false - -############## EnergyVariable, Storage #################### -get_variable_binary(::EnergyVariable, ::Type{<:PSY.Storage}, ::AbstractStorageFormulation) = false -get_variable_upper_bound(::EnergyVariable, d::PSY.Storage, ::AbstractStorageFormulation) = PSY.get_state_of_charge_limits(d).max -get_variable_lower_bound(::EnergyVariable, d::PSY.Storage, ::AbstractStorageFormulation) = PSY.get_state_of_charge_limits(d).min -get_variable_warm_start_value(::EnergyVariable, d::PSY.Storage, ::AbstractStorageFormulation) = PSY.get_initial_energy(d) - -############## ReservationVariable, Storage #################### -get_variable_binary(::ReservationVariable, ::Type{<:PSY.Storage}, ::AbstractStorageFormulation) = true -get_efficiency(v::T, var::Type{<:InitialConditionType}) where T <: PSY.Storage = PSY.get_efficiency(v) - -############## EnergyShortageVariable, Storage #################### -get_variable_binary(::EnergyShortageVariable, ::Type{<:PSY.Storage}, ::AbstractStorageFormulation) = false -get_variable_lower_bound(::EnergyShortageVariable, d::PSY.Storage, ::AbstractStorageFormulation) = 0.0 -get_variable_upper_bound(::EnergyShortageVariable, d::PSY.Storage, ::AbstractStorageFormulation) = PSY.get_state_of_charge_limits(d).max - -############## EnergySurplusVariable, Storage #################### -get_variable_binary(::EnergySurplusVariable, ::Type{<:PSY.Storage}, ::AbstractStorageFormulation) = false -get_variable_upper_bound(::EnergySurplusVariable, d::PSY.Storage, ::AbstractStorageFormulation) = 0.0 -get_variable_lower_bound(::EnergySurplusVariable, d::PSY.Storage, ::AbstractStorageFormulation) = - PSY.get_state_of_charge_limits(d).max - -#################### Initial Conditions for models ############### -initial_condition_default(::InitialEnergyLevel, d::PSY.Storage, ::AbstractStorageFormulation) = PSY.get_initial_energy(d) -initial_condition_variable(::InitialEnergyLevel, d::PSY.Storage, ::AbstractStorageFormulation) = EnergyVariable() - -########################### Parameter related set functions ################################ -get_parameter_multiplier(::VariableValueParameter, d::PSY.Storage, ::AbstractStorageFormulation) = 1.0 -get_initial_parameter_value(::VariableValueParameter, d::PSY.Storage, ::AbstractStorageFormulation) = 1.0 - - -########################Objective Function################################################## -objective_function_multiplier(::VariableType, ::AbstractStorageFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::EnergySurplusVariable, ::EnergyTarget)=OBJECTIVE_FUNCTION_NEGATIVE -objective_function_multiplier(::EnergyShortageVariable, ::EnergyTarget)=OBJECTIVE_FUNCTION_POSITIVE - -proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.BatteryEMS, ::EnergyTarget)=PSY.get_energy_surplus_cost(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.BatteryEMS, ::EnergyTarget)=PSY.get_energy_shortage_cost(cost) - -variable_cost(cost::PSY.StorageManagementCost, ::ActivePowerOutVariable, ::PSY.BatteryEMS, ::EnergyTarget)=PSY.get_variable(cost) - - -#! format: on - -get_initial_conditions_device_model( - ::OperationModel, - ::DeviceModel{T, <:AbstractStorageFormulation}, -) where {T <: PSY.Storage} = DeviceModel(T, BookKeeping) - -get_multiplier_value( - ::EnergyTargetTimeSeriesParameter, - d::PSY.Storage, - ::AbstractStorageFormulation, -) = PSY.get_rating(d) - -function get_default_time_series_names( - ::Type{D}, - ::Type{EnergyTarget}, -) where {D <: PSY.Storage} - return Dict{Type{<:TimeSeriesParameter}, String}( - EnergyTargetTimeSeriesParameter => "storage_target", - ) -end - -function get_default_time_series_names( - ::Type{D}, - ::Type{<:Union{FixedOutput, AbstractStorageFormulation}}, -) where {D <: PSY.Storage} - return Dict{Type{<:TimeSeriesParameter}, String}() -end - -function get_default_attributes( - ::Type{D}, - ::Type{T}, -) where {D <: PSY.Storage, T <: Union{FixedOutput, AbstractStorageFormulation}} - return Dict{String, Any}("reservation" => true) -end - -################################## output power constraints################################# - -get_min_max_limits( - device::PSY.Storage, - ::Type{<:ReactivePowerVariableLimitsConstraint}, - ::Type{<:AbstractStorageFormulation}, -) = PSY.get_reactive_power_limits(device) -get_min_max_limits( - device::PSY.Storage, - ::Type{<:InputActivePowerVariableLimitsConstraint}, - ::Type{<:AbstractStorageFormulation}, -) = PSY.get_input_active_power_limits(device) -get_min_max_limits( - device::PSY.Storage, - ::Type{<:OutputActivePowerVariableLimitsConstraint}, - ::Type{<:AbstractStorageFormulation}, -) = PSY.get_output_active_power_limits(device) -get_min_max_limits( - device::PSY.Storage, - ::Type{<:OutputActivePowerVariableLimitsConstraint}, - ::Type{BookKeeping}, -) = PSY.get_output_active_power_limits(device) - -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.Storage, W <: AbstractStorageFormulation, X <: PM.AbstractPowerModel} - if get_attribute(model, "reservation") - add_reserve_range_constraints!(container, T, U, devices, model, X) - else - add_range_constraints!(container, T, U, devices, model, X) - end -end - -########################## Make initial Conditions for a Model ############################# -function initial_conditions!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{St}, - formulation::AbstractStorageFormulation, -) where {St <: PSY.Storage} - add_initial_condition!(container, devices, formulation, InitialEnergyLevel()) - return -end - -############################ Energy Capacity Constraints#################################### -""" -Min and max limits for Energy Capacity Constraint and AbstractStorageFormulation -""" -function get_min_max_limits( - d, - ::Type{EnergyCapacityConstraint}, - ::Type{<:AbstractStorageFormulation}, -) - return PSY.get_state_of_charge_limits(d) -end - -""" -Add Energy Capacity Constraints for AbstractStorageFormulation -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyCapacityConstraint}, - ::Type{<:VariableType}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - network_model::NetworkModel{X}, -) where {V <: PSY.Storage, W <: AbstractStorageFormulation, X <: PM.AbstractPowerModel} - add_range_constraints!( - container, - EnergyCapacityConstraint, - EnergyVariable, - devices, - model, - X, - ) - return -end - -############################ book keeping constraints ###################################### - -""" -Add Energy Balance Constraints for AbstractStorageFormulation -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyBalanceConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - network_model::NetworkModel{X}, -) where {V <: PSY.Storage, W <: AbstractStorageFormulation, X <: PM.AbstractPowerModel} - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - names = [PSY.get_name(x) for x in devices] - initial_conditions = get_initial_condition(container, InitialEnergyLevel(), V) - energy_var = get_variable(container, EnergyVariable(), V) - powerin_var = get_variable(container, ActivePowerInVariable(), V) - powerout_var = get_variable(container, ActivePowerOutVariable(), V) - - constraint = add_constraints_container!( - container, - EnergyBalanceConstraint(), - V, - names, - time_steps, - ) - - for ic in initial_conditions - device = get_component(ic) - efficiency = PSY.get_efficiency(device) - name = PSY.get_name(device) - constraint[name, 1] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, 1] == - get_value(ic) + - ( - powerin_var[name, 1] * efficiency.in - - (powerout_var[name, 1] / efficiency.out) - ) * fraction_of_hour - ) - - for t in time_steps[2:end] - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, t] == - energy_var[name, t - 1] + - ( - powerin_var[name, t] * efficiency.in - - (powerout_var[name, t] / efficiency.out) - ) * fraction_of_hour - ) - end - end - return -end - -############################ reserve constraints ###################################### -function add_constraints!( - container::OptimizationContainer, - ::Type{ReserveEnergyCoverageConstraint}, - devices::IS.FlattenIteratorWrapper{T}, - model::DeviceModel{T, U}, - network_model::NetworkModel{V}, -) where {T <: PSY.Storage, U <: AbstractStorageFormulation, V <: PM.AbstractPowerModel} - time_steps = get_time_steps(container) - var_e = get_variable(container, EnergyVariable(), T) - expr_up = get_expression(container, ReserveRangeExpressionUB(), T) - expr_dn = get_expression(container, ReserveRangeExpressionLB(), T) - names = [PSY.get_name(x) for x in devices] - con_up = add_constraints_container!( - container, - ReserveEnergyCoverageConstraint(), - T, - names, - time_steps; - meta = "up", - ) - con_dn = add_constraints_container!( - container, - ReserveEnergyCoverageConstraint(), - T, - names, - time_steps; - meta = "dn", - ) - - for d in devices, t in time_steps - name = PSY.get_name(d) - limits = PSY.get_state_of_charge_limits(d) - efficiency = PSY.get_efficiency(d) - con_up[name, t] = JuMP.@constraint( - container.JuMPmodel, - expr_up[name, t] <= (var_e[name, t] - limits.min) * efficiency.out - ) - con_dn[name, t] = JuMP.@constraint( - container.JuMPmodel, - expr_dn[name, t] <= (limits.max - var_e[name, t]) / efficiency.in - ) - end - return -end - -function add_constraints!( - container::OptimizationContainer, - ::Type{RangeLimitConstraint}, - devices::IS.FlattenIteratorWrapper{T}, - model::DeviceModel{T, D}, - network_model::NetworkModel{V}, -) where {T <: PSY.Storage, D <: AbstractStorageFormulation, V <: PM.AbstractPowerModel} - time_steps = get_time_steps(container) - var_in = get_variable(container, ActivePowerInVariable(), T) - var_out = get_variable(container, ActivePowerOutVariable(), T) - expr_up = get_expression(container, ReserveRangeExpressionUB(), T) - expr_dn = get_expression(container, ReserveRangeExpressionLB(), T) - names = [PSY.get_name(x) for x in devices] - con_up = add_constraints_container!( - container, - RangeLimitConstraint(), - T, - names, - time_steps; - meta = "up", - ) - con_dn = add_constraints_container!( - container, - RangeLimitConstraint(), - T, - names, - time_steps; - meta = "dn", - ) - - for d in devices, t in time_steps - name = PSY.get_name(d) - out_limits = PSY.get_output_active_power_limits(d) - in_limits = PSY.get_input_active_power_limits(d) - con_up[name, t] = JuMP.@constraint( - container.JuMPmodel, - expr_up[name, t] <= var_in[name, t] + (out_limits.max - var_out[name, t]) - ) - con_dn[name, t] = JuMP.@constraint( - container.JuMPmodel, - expr_dn[name, t] <= var_out[name, t] + (in_limits.max - var_in[name, t]) - ) - end - return -end - -############################ Energy Management constraints ###################################### -""" -Add Energy Target Constraints for EnergyTarget formulation -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyTargetConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - network_model::NetworkModel{X}, -) where {V <: PSY.Storage, W <: EnergyTarget, X <: PM.AbstractPowerModel} - time_steps = get_time_steps(container) - name_index = [PSY.get_name(d) for d in devices] - energy_var = get_variable(container, EnergyVariable(), V) - shortage_var = get_variable(container, EnergyShortageVariable(), V) - surplus_var = get_variable(container, EnergySurplusVariable(), V) - - param_container = get_parameter(container, EnergyTargetTimeSeriesParameter(), V) - multiplier = get_multiplier_array(param_container) - - constraint = add_constraints_container!( - container, - EnergyTargetConstraint(), - V, - name_index, - time_steps, - ) - for d in devices - name = PSY.get_name(d) - shortage_cost = PSY.get_energy_shortage_cost(PSY.get_operation_cost(d)) - if shortage_cost == 0.0 - @warn( - "Device $name has energy shortage cost set to 0.0, as a result the model will turnoff the EnergyShortageVariable to avoid infeasible/unbounded problem." - ) - JuMP.delete_upper_bound.(shortage_var[name, :]) - JuMP.set_upper_bound.(shortage_var[name, :], 0.0) - end - for t in time_steps - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, t] + shortage_var[name, t] + surplus_var[name, t] == - multiplier[name, t] * get_parameter_column_refs(param_container, name)[t] - ) - end - end - return -end - -##################################### Storage generation cost ############################ -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{V}, -) where {T <: PSY.Storage, U <: AbstractStorageFormulation, V <: PM.AbstractPowerModel} - add_proportional_cost!(container, ActivePowerOutVariable(), devices, U()) - add_proportional_cost!(container, ActivePowerInVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{PSY.BatteryEMS}, - ::DeviceModel{PSY.BatteryEMS, T}, - ::Type{V}, -) where {T <: EnergyTarget, V <: PM.AbstractPowerModel} - add_variable_cost!(container, ActivePowerOutVariable(), devices, T()) - add_proportional_cost!(container, EnergySurplusVariable(), devices, T()) - add_proportional_cost!(container, EnergyShortageVariable(), devices, T()) - return -end diff --git a/test/test_device_storage_constructors.jl b/test/test_device_storage_constructors.jl deleted file mode 100644 index 395d167604..0000000000 --- a/test/test_device_storage_constructors.jl +++ /dev/null @@ -1,314 +0,0 @@ -@testset "Storage Basic Storage With DC - PF" begin - device_model = DeviceModel( - GenericBattery, - BookKeeping; - attributes = Dict{String, Any}("reservation" => false), - ) - c_sys5_bat = PSB.build_system(PSITestSystems, "c_sys5_bat") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_bat) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 72, 24, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Storage Basic Storage With AC - PF" begin - device_model = DeviceModel( - GenericBattery, - BookKeeping; - attributes = Dict{String, Any}("reservation" => false), - ) - c_sys5_bat = PSB.build_system(PSITestSystems, "c_sys5_bat") - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_bat) - mock_construct_device!(model, device_model) - moi_tests(model, 96, 0, 96, 96, 24, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Storage with Reservation & DC - PF" begin - device_model = DeviceModel(GenericBattery, BookKeeping) - c_sys5_bat = PSB.build_system(PSITestSystems, "c_sys5_bat") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_bat) - mock_construct_device!(model, device_model) - moi_tests(model, 96, 0, 72, 72, 24, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Storage with Reservation & AC - PF" begin - device_model = DeviceModel(GenericBattery, BookKeeping) - c_sys5_bat = PSB.build_system(PSITestSystems, "c_sys5_bat") - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_bat) - mock_construct_device!(model, device_model) - moi_tests(model, 120, 0, 96, 96, 24, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Storage with BatteryAncillaryServices and Reservation DC - PF" begin - device_model = DeviceModel(GenericBattery, BatteryAncillaryServices) - c_sys5_bat = PSB.build_system(PSITestSystems, "c_sys5_bat") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_bat) - mock_construct_device!(model, device_model) - moi_tests(model, 96, 0, 72, 72, 24, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Storage with BatteryAncillaryServices and Reservation With AC - PF" begin - device_model = DeviceModel(GenericBattery, BatteryAncillaryServices) - c_sys5_bat = PSB.build_system(PSITestSystems, "c_sys5_bat") - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_bat) - mock_construct_device!(model, device_model) - moi_tests(model, 120, 0, 96, 96, 24, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "BatteryEMS with EnergyTarget with DC - PF" begin - device_model = DeviceModel(BatteryEMS, EnergyTarget) - c_sys5_bat = PSB.build_system(PSITestSystems, "c_sys5_bat_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_bat) - mock_construct_device!(model, device_model) - moi_tests(model, 144, 0, 72, 72, 48, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "BatteryEMS with EnergyTarget With AC - PF" begin - device_model = DeviceModel(BatteryEMS, EnergyTarget) - c_sys5_bat = PSB.build_system(PSITestSystems, "c_sys5_bat_ems") - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_bat) - mock_construct_device!(model, device_model) - moi_tests(model, 168, 0, 96, 96, 48, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "BatteryEMS with EnergyTarget Formulations (energy target - cases 1b-2b" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, BatteryEMS, EnergyTarget) - set_device_model!(template, RenewableDispatch, RenewableFullDispatch) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5 = PSB.build_system(PSITestSystems, "batt_test_case_b_sys") - model = - DecisionModel( - EconomicDispatchProblem, - template, - c_sys5; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 21, 0, 12, 9, 9, true) - psi_checksolve_test(model, [MOI.OPTIMAL], 5811.0, 10.0) -end - -@testset "BatteryEMS with EnergyTarget Formulations (energy target - cases 1c-2c" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, BatteryEMS, EnergyTarget) - set_device_model!(template, RenewableDispatch, RenewableFullDispatch) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5 = PSB.build_system(PSITestSystems, "batt_test_case_c_sys") - - model = - DecisionModel( - EconomicDispatchProblem, - template, - c_sys5; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 21, 0, 12, 9, 9, true) - psi_checksolve_test(model, [MOI.OPTIMAL], -63.0, 10.0) -end - -@testset "BatteryEMS with EnergyTarget Formulations (energy target - cases 1d-2d" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, BatteryEMS, EnergyTarget) - set_device_model!(template, RenewableDispatch, RenewableFullDispatch) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5 = PSB.build_system(PSITestSystems, "batt_test_case_d_sys") - - model = - DecisionModel( - EconomicDispatchProblem, - template, - c_sys5; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 28, 0, 16, 12, 12, true) - psi_checksolve_test(model, [MOI.OPTIMAL], -11118.0, 10.0) -end - -@testset "BatteryEMS with EnergyTarget Formulations (energy target - cases 1e-2e" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, BatteryEMS, EnergyTarget) - set_device_model!(template, RenewableDispatch, RenewableFullDispatch) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5 = PSB.build_system(PSITestSystems, "batt_test_case_e_sys") - model = - DecisionModel( - EconomicDispatchProblem, - template, - c_sys5; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 21, 0, 12, 9, 9, true) - psi_checksolve_test(model, [MOI.OPTIMAL], 5547.0, 10.0) -end - -@testset "BatteryEMS with EnergyTarget Formulations (energy target - cases 1f-2f" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, BatteryEMS, EnergyTarget) - set_device_model!(template, RenewableDispatch, RenewableFullDispatch) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5 = PSB.build_system(PSITestSystems, "batt_test_case_f_sys") - - model = - DecisionModel( - EconomicDispatchProblem, - template, - c_sys5; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 21, 0, 12, 9, 9, true) - psi_checksolve_test(model, [MOI.OPTIMAL], -1825.0, 10.0) -end - -### Feedforward Test ### - -@testset "Test EnergyTargetFeedforward to GenericBattery with BookKeeping model" begin - device_model = DeviceModel(GenericBattery, BookKeeping) - - ff_et = EnergyTargetFeedforward(; - component_type = GenericBattery, - source = EnergyVariable, - affected_values = [EnergyVariable], - target_period = 12, - penalty_cost = 1e5, - ) - - PSI.attach_feedforward!(device_model, ff_et) - sys = PSB.build_system(PSITestSystems, "c_sys5_bat") - model = DecisionModel(MockOperationProblem, DCPPowerModel, sys) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 145, 0, 72, 73, 24, true) -end - -@testset "Test EnergyLimitFeedforward to GenericBattery with BookKeeping model" begin - device_model = DeviceModel(GenericBattery, BookKeeping) - - ff_il = EnergyLimitFeedforward(; - component_type = GenericBattery, - source = ActivePowerOutVariable, - affected_values = [ActivePowerOutVariable], - number_of_periods = 12, - ) - - PSI.attach_feedforward!(device_model, ff_il) - sys = PSB.build_system(PSITestSystems, "c_sys5_bat") - model = DecisionModel(MockOperationProblem, DCPPowerModel, sys) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 121, 0, 74, 72, 24, true) -end - -@testset "Test EnergyTargetFeedforward to GenericBattery with BookKeeping model" begin - device_model = DeviceModel(GenericBattery, BatteryAncillaryServices) - - ff_et = EnergyTargetFeedforward(; - component_type = GenericBattery, - source = EnergyVariable, - affected_values = [EnergyVariable], - target_period = 12, - penalty_cost = 1e5, - ) - - PSI.attach_feedforward!(device_model, ff_et) - sys = PSB.build_system(PSITestSystems, "c_sys5_bat") - model = DecisionModel(MockOperationProblem, DCPPowerModel, sys) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 145, 0, 72, 73, 24, true) -end - -@testset "Test EnergyLimitFeedforward to GenericBattery with BatteryAncillaryServices model" begin - device_model = DeviceModel(GenericBattery, BatteryAncillaryServices) - - ff_il = EnergyLimitFeedforward(; - component_type = GenericBattery, - source = ActivePowerOutVariable, - affected_values = [ActivePowerOutVariable], - number_of_periods = 12, - ) - - PSI.attach_feedforward!(device_model, ff_il) - sys = PSB.build_system(PSITestSystems, "c_sys5_bat") - model = DecisionModel(MockOperationProblem, DCPPowerModel, sys) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 121, 0, 74, 72, 24, true) -end - -@testset "Test EnergyTargetFeedforward to GenericBattery with BookKeeping model" begin - device_model = DeviceModel(BatteryEMS, BookKeeping) - - ff_et = EnergyTargetFeedforward(; - component_type = BatteryEMS, - source = EnergyVariable, - affected_values = [EnergyVariable], - target_period = 12, - penalty_cost = 1e5, - ) - - PSI.attach_feedforward!(device_model, ff_et) - sys = PSB.build_system(PSITestSystems, "c_sys5_bat_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, sys) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 145, 0, 72, 73, 24, true) -end - -@testset "Test EnergyLimitFeedforward to BatteryEMS with BookKeeping model" begin - device_model = DeviceModel(BatteryEMS, BookKeeping) - - ff_il = EnergyLimitFeedforward(; - component_type = BatteryEMS, - source = ActivePowerOutVariable, - affected_values = [ActivePowerOutVariable], - number_of_periods = 12, - ) - - PSI.attach_feedforward!(device_model, ff_il) - sys = PSB.build_system(PSITestSystems, "c_sys5_bat_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, sys) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 121, 0, 74, 72, 24, true) -end - -@testset "Test EnergyTargetFeedforward to GenericBattery with BatteryAncillaryServices model" begin - device_model = DeviceModel(BatteryEMS, BatteryAncillaryServices) - - ff_et = EnergyTargetFeedforward(; - component_type = BatteryEMS, - source = EnergyVariable, - affected_values = [EnergyVariable], - target_period = 12, - penalty_cost = 1e5, - ) - - PSI.attach_feedforward!(device_model, ff_et) - sys = PSB.build_system(PSITestSystems, "c_sys5_bat_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, sys) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 145, 0, 72, 73, 24, true) -end - -@testset "Test EnergyLimitFeedforward to BatteryEMS with BatteryAncillaryServices model" begin - device_model = DeviceModel(BatteryEMS, BatteryAncillaryServices) - - ff_il = EnergyLimitFeedforward(; - component_type = BatteryEMS, - source = ActivePowerOutVariable, - affected_values = [ActivePowerOutVariable], - number_of_periods = 12, - ) - - PSI.attach_feedforward!(device_model, ff_il) - sys = PSB.build_system(PSITestSystems, "c_sys5_bat_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, sys) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 121, 0, 74, 72, 24, true) -end diff --git a/test/test_model_decision.jl b/test/test_model_decision.jl index 00f54c2622..15750d6f35 100644 --- a/test/test_model_decision.jl +++ b/test/test_model_decision.jl @@ -455,35 +455,6 @@ end @test solve!(model) == RunStatus.SUCCESSFUL end -@testset "Decision Model initial_conditions test for Storage" begin - ######## Test with BookKeeping ######## - template = get_thermal_dispatch_template_network() - c_sys5_bat = PSB.build_system(PSITestSystems, "c_sys5_bat"; force_build = true) - set_device_model!(template, GenericBattery, BookKeeping) - model = DecisionModel(template, c_sys5_bat; optimizer = HiGHS_optimizer) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == BuildStatus.BUILT - check_energy_initial_conditions_values(model, GenericBattery) - @test solve!(model) == RunStatus.SUCCESSFUL - - ######## Test with BatteryAncillaryServices ######## - template = get_thermal_dispatch_template_network() - c_sys5_bat = PSB.build_system(PSITestSystems, "c_sys5_bat"; force_build = true) - set_device_model!(template, GenericBattery, BatteryAncillaryServices) - model = DecisionModel(template, c_sys5_bat; optimizer = HiGHS_optimizer) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == BuildStatus.BUILT - check_energy_initial_conditions_values(model, GenericBattery) - @test solve!(model) == RunStatus.SUCCESSFUL - - ######## Test with EnergyTarget ######## - template = get_thermal_dispatch_template_network() - c_sys5_bat = PSB.build_system(PSITestSystems, "c_sys5_bat_ems"; force_build = true) - set_device_model!(template, BatteryEMS, EnergyTarget) - model = DecisionModel(template, c_sys5_bat; optimizer = HiGHS_optimizer) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == BuildStatus.BUILT - check_energy_initial_conditions_values(model, BatteryEMS) - @test solve!(model) == RunStatus.SUCCESSFUL -end - @testset "Decision Model initial_conditions test for Hydro" begin ######## Test with HydroDispatchRunOfRiver ######## template = get_thermal_dispatch_template_network() diff --git a/test/test_model_emulation.jl b/test/test_model_emulation.jl index 7771d8600d..ba40caa9ba 100644 --- a/test/test_model_emulation.jl +++ b/test/test_model_emulation.jl @@ -97,80 +97,6 @@ end BuildStatus.BUILT end -@testset "Emulation Model initial_conditions test for Storage" begin - ######## Test with BookKeeping ######## - template = get_thermal_dispatch_template_network() - c_sys5_bat = PSB.build_system( - PSITestSystems, - "c_sys5_bat"; - add_single_time_series = true, - force_build = true, - ) - set_device_model!(template, GenericBattery, BookKeeping) - model = EmulationModel(template, c_sys5_bat; optimizer = HiGHS_optimizer) - @test build!(model; executions = 10, output_dir = mktempdir(; cleanup = true)) == - BuildStatus.BUILT - ic_data = PSI.get_initial_condition( - PSI.get_optimization_container(model), - InitialEnergyLevel(), - GenericBattery, - ) - for ic in ic_data - name = PSY.get_name(ic.component) - e_var = PSI.jump_value(PSI.get_value(ic)) - @test PSY.get_initial_energy(ic.component) == e_var - end - @test run!(model) == RunStatus.SUCCESSFUL - - ######## Test with BatteryAncillaryServices ######## - template = get_thermal_dispatch_template_network() - c_sys5_bat = PSB.build_system( - PSITestSystems, - "c_sys5_bat"; - add_single_time_series = true, - force_build = true, - ) - set_device_model!(template, GenericBattery, BatteryAncillaryServices) - model = EmulationModel(template, c_sys5_bat; optimizer = HiGHS_optimizer) - @test build!(model; executions = 10, output_dir = mktempdir(; cleanup = true)) == - BuildStatus.BUILT - ic_data = PSI.get_initial_condition( - PSI.get_optimization_container(model), - InitialEnergyLevel(), - GenericBattery, - ) - for ic in ic_data - name = PSY.get_name(ic.component) - e_var = PSI.jump_value(PSI.get_value(ic)) - @test PSY.get_initial_energy(ic.component) == e_var - end - @test run!(model) == RunStatus.SUCCESSFUL - - ######## Test with EnergyTarget ######## - template = get_thermal_dispatch_template_network() - c_sys5_bat = PSB.build_system( - PSITestSystems, - "c_sys5_bat_ems"; - add_single_time_series = true, - force_build = true, - ) - set_device_model!(template, BatteryEMS, EnergyTarget) - model = EmulationModel(template, c_sys5_bat; optimizer = HiGHS_optimizer) - @test build!(model; executions = 10, output_dir = mktempdir(; cleanup = true)) == - BuildStatus.BUILT - ic_data = PSI.get_initial_condition( - PSI.get_optimization_container(model), - InitialEnergyLevel(), - BatteryEMS, - ) - for ic in ic_data - name = PSY.get_name(ic.component) - e_var = PSI.jump_value(PSI.get_value(ic)) - @test PSY.get_initial_energy(ic.component) == e_var - end - @test run!(model) == RunStatus.SUCCESSFUL -end - @testset "Emulation Model initial_conditions test for Hydro" begin ######## Test with HydroDispatchRunOfRiver ######## template = get_thermal_dispatch_template_network() From 6e0dc8000816dbdb7b5f1a4b2392c8ecb4f04dec Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 24 Apr 2023 12:25:18 -0600 Subject: [PATCH 093/370] remove more code --- docs/make.jl | 1 - .../devices/common/objective_functions.jl | 19 ------ test/test_services_constructor.jl | 23 ------- test/test_simulation_execute.jl | 63 ------------------- 4 files changed, 106 deletions(-) diff --git a/docs/make.jl b/docs/make.jl index 8fd65bd2e2..79e1b01122 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -32,7 +32,6 @@ pages = OrderedDict( "Thermal Generation" => "formulation_library/ThermalGen.md", "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", - "Storage" => "formulation_library/Storage.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", "Branch" => "formulation_library/Branch.md", diff --git a/src/devices_models/devices/common/objective_functions.jl b/src/devices_models/devices/common/objective_functions.jl index 210135aed4..87bf5faca2 100644 --- a/src/devices_models/devices/common/objective_functions.jl +++ b/src/devices_models/devices/common/objective_functions.jl @@ -76,25 +76,6 @@ function add_proportional_cost!( return end -function add_proportional_cost!( - container::OptimizationContainer, - ::U, - devices::IS.FlattenIteratorWrapper{T}, - ::V, -) where { - T <: PSY.Storage, - U <: Union{ActivePowerInVariable, ActivePowerOutVariable}, - V <: AbstractDeviceFormulation, -} - multiplier = objective_function_multiplier(U(), V()) - for d in devices - for t in get_time_steps(container) - _add_proportional_term!(container, U(), d, COST_EPSILON * multiplier, t) - end - end - return -end - function add_proportional_cost!( container::OptimizationContainer, ::U, diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index 981df03510..4fd3a477a1 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -132,29 +132,6 @@ end moi_tests(model, 360, 0, 72, 48, 72, false) end -@testset "Test Reserves from Storage" begin - template = get_thermal_dispatch_template_network(CopperPlatePowerModel) - set_device_model!(template, DeviceModel(GenericBattery, BatteryAncillaryServices)) - set_device_model!(template, RenewableDispatch, FixedOutput) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve3"), - ) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveDown}, RangeReserve, "Reserve4"), - ) - set_service_model!( - template, - ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), - ) - - c_sys5_bat = PSB.build_system(PSITestSystems, "c_sys5_bat"; add_reserves = true) - model = DecisionModel(template, c_sys5_bat) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 432, 0, 288, 264, 96, true) -end - @testset "Test Reserves from Hydro" begin template = ProblemTemplate(CopperPlatePowerModel) set_device_model!(template, PowerLoad, StaticPowerLoad) diff --git a/test/test_simulation_execute.jl b/test/test_simulation_execute.jl index 7909891ab6..783c4c5241 100644 --- a/test/test_simulation_execute.jl +++ b/test/test_simulation_execute.jl @@ -110,69 +110,6 @@ end end end -function test_2_stages_with_storage_ems(in_memory) - template_uc = - get_template_hydro_st_uc(NetworkModel(CopperPlatePowerModel; use_slacks = true)) - template_ed = - get_template_hydro_st_ed(NetworkModel(CopperPlatePowerModel; use_slacks = true)) - set_device_model!(template_ed, InterruptiblePowerLoad, StaticPowerLoad) - c_sys5_hy_uc = PSB.build_system(PSITestSystems, "c_sys5_hy_ems_uc") - c_sys5_hy_ed = PSB.build_system(PSITestSystems, "c_sys5_hy_ems_ed") - models = SimulationModels(; - decision_models = [ - DecisionModel( - template_uc, - c_sys5_hy_uc; - name = "UC", - optimizer = GLPK_optimizer, - ), - DecisionModel( - template_ed, - c_sys5_hy_ed; - name = "ED", - optimizer = GLPK_optimizer, - ), - ], - ) - - sequence_cache = SimulationSequence(; - models = models, - feedforwards = Dict( - "ED" => [ - SemiContinuousFeedforward(; - component_type = ThermalStandard, - source = OnVariable, - affected_values = [ActivePowerVariable], - ), - EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ), - ], - ), - ini_cond_chronology = InterProblemChronology(), - ) - sim_cache = Simulation(; - name = "cache", - steps = 2, - models = models, - sequence = sequence_cache, - simulation_folder = mktempdir(; cleanup = true), - ) - build_out = build!(sim_cache) - @test build_out == PSI.BuildStatus.BUILT - execute_out = execute!(sim_cache; in_memory = in_memory) - @test execute_out == PSI.RunStatus.SUCCESSFUL -end - -@testset "Simulation with 2-Stages with Storage EMS" begin - for in_memory in (true, false) - test_2_stages_with_storage_ems(in_memory) - end -end - @testset "Test Simulation Utils" begin template_uc = get_template_basic_uc_simulation() set_device_model!(template_uc, ThermalStandard, ThermalStandardUnitCommitment) From 6d7e8ae80e74bfe907bc4494d832f7f79c2261d2 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 1 May 2023 11:22:39 -0600 Subject: [PATCH 094/370] rename branch --- .github/workflows/docs.yml | 2 +- .github/workflows/format-check.yml | 2 +- .github/workflows/{master-tests.yml => main-tests.yml} | 4 ++-- .github/workflows/performance_comparison.yml | 6 +++--- README.md | 8 ++++---- docs/make.jl | 2 +- docs/src/code_base_developer_guide/developer.md | 2 +- docs/src/index.md | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) rename .github/workflows/{master-tests.yml => main-tests.yml} (96%) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index fa466af289..e53ea5da3b 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -3,7 +3,7 @@ name: Documentation on: push: branches: - - master + - main - 'release-' tags: '*' pull_request: diff --git a/.github/workflows/format-check.yml b/.github/workflows/format-check.yml index 75786f59cb..cf2bed076a 100644 --- a/.github/workflows/format-check.yml +++ b/.github/workflows/format-check.yml @@ -3,7 +3,7 @@ name: Format Check on: push: branches: - - 'master' + - 'main' - 'release-' tags: '*' pull_request: diff --git a/.github/workflows/master-tests.yml b/.github/workflows/main-tests.yml similarity index 96% rename from .github/workflows/master-tests.yml rename to .github/workflows/main-tests.yml index e1b8905b3f..0fdaa6aa15 100644 --- a/.github/workflows/master-tests.yml +++ b/.github/workflows/main-tests.yml @@ -1,9 +1,9 @@ -name: Master - CI +name: Main - CI on: push: branches: - - master + - main schedule: - cron: 0 * * * * jobs: diff --git a/.github/workflows/performance_comparison.yml b/.github/workflows/performance_comparison.yml index 460f80c159..a946c87002 100644 --- a/.github/workflows/performance_comparison.yml +++ b/.github/workflows/performance_comparison.yml @@ -9,10 +9,10 @@ jobs: steps: - uses: julia-actions/setup-julia@latest - uses: actions/checkout@v1 - - name: Run Perfomance Test Master + - name: Run Perfomance Test Main run: | - julia --project=test -e 'using Pkg; Pkg.add(PackageSpec(name="PowerSimulations", rev="master")); Pkg.instantiate()' - julia -t 4 --project=test test/performance/performance_test.jl "Master" + julia --project=test -e 'using Pkg; Pkg.add(PackageSpec(name="PowerSimulations", rev="main")); Pkg.instantiate()' + julia -t 4 --project=test test/performance/performance_test.jl "Main" - name: Run Perfomance Test Branch run: | julia --project=test -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' diff --git a/README.md b/README.md index 74567b9d9b..5f8ed59fcb 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # PowerSimulations.jl -[![Master - CI](https://github.com/NREL-Sienna/PowerSimulations.jl/actions/workflows/master-tests.yml/badge.svg)](https://github.com/NREL-Sienna/PowerSimulations.jl/actions/workflows/master-tests.yml) -[![codecov](https://codecov.io/gh/NREL-Sienna/PowerSimulations.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/NREL-Sienna/PowerSimulations.jl) +[![Main - CI](https://github.com/NREL-Sienna/PowerSimulations.jl/actions/workflows/main-tests.yml/badge.svg)](https://github.com/NREL-Sienna/PowerSimulations.jl/actions/workflows/main-tests.yml) +[![codecov](https://codecov.io/gh/NREL-Sienna/PowerSimulations.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/NREL-Sienna/PowerSimulations.jl) [![Documentation](https://github.com/NREL-Sienna/PowerSimulations.jl/workflows/Documentation/badge.svg)](https://nrel-sienna.github.io/PowerSimulations.jl/latest) [![DOI](https://zenodo.org/badge/109443246.svg)](https://zenodo.org/badge/latestdoi/109443246) [](https://join.slack.com/t/nrel-siip/shared_invite/zt-glam9vdu-o8A9TwZTZqqNTKHa7q3BpQ) @@ -50,9 +50,9 @@ using PowerSystems ## Development -Contributions to the development and enhancement of PowerSimulations is welcome. Please see [CONTRIBUTING.md](https://github.com/NREL-Sienna/PowerSimulations.jl/blob/master/CONTRIBUTING.md) for code contribution guidelines. +Contributions to the development and enhancement of PowerSimulations is welcome. Please see [CONTRIBUTING.md](https://github.com/NREL-Sienna/PowerSimulations.jl/blob/main/CONTRIBUTING.md) for code contribution guidelines. ## License -PowerSimulations is released under a BSD [license](https://github.com/NREL/PowerSimulations.jl/blob/master/LICENSE). PowerSimulations has been developed as part of the Scalable Integrated Infrastructure Planning (SIIP) +PowerSimulations is released under a BSD [license](https://github.com/NREL/PowerSimulations.jl/blob/main/LICENSE). PowerSimulations has been developed as part of the Scalable Integrated Infrastructure Planning (SIIP) initiative at the U.S. Department of Energy's National Renewable Energy Laboratory ([NREL](https://www.nrel.gov/)) diff --git a/docs/make.jl b/docs/make.jl index 79e1b01122..0fc90a93a8 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -51,7 +51,7 @@ deploydocs(; repo = "github.com/NREL-Sienna/PowerSimulations.jl.git", target = "build", branch = "gh-pages", - devbranch = "master", + devbranch = "main", devurl = "dev", push_preview = true, versions = ["stable" => "v^", "v#.#"], diff --git a/docs/src/code_base_developer_guide/developer.md b/docs/src/code_base_developer_guide/developer.md index 5a278e1072..0e38b054f7 100644 --- a/docs/src/code_base_developer_guide/developer.md +++ b/docs/src/code_base_developer_guide/developer.md @@ -5,7 +5,7 @@ In order to contribute to `PowerSystems.jl` repository please read the following documentation in detail: 1. [Style Guide](https://nrel-siip.github.io/InfrastructureSystems.jl/stable/style/) -2. [Contributing Guidelines](https://github.com/NREL-Sienna/PowerSystems.jl/blob/master/CONTRIBUTING.md) +2. [Contributing Guidelines](https://github.com/NREL-Sienna/PowerSystems.jl/blob/main/CONTRIBUTING.md) Pull requests are always welcome to fix bugs or add additional modeling capabilities. diff --git a/docs/src/index.md b/docs/src/index.md index b0e59b4721..ba3418e5cf 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -43,7 +43,7 @@ The latest stable release of PowerModels can be installed using the Julia packag For the current development version, "checkout" this package with ```julia -] add PowerSimulations#master +] add PowerSimulations#main ``` An appropriate optimization solver is required for running PowerSimulations models. Refer to [`JuMP.jl` solver's page](https://jump.dev/JuMP.jl/stable/installation/#Install-a-solver) to select the most appropriate for the application of interest. From bd95ff370efeb24dffb2b4addbb38f82b8f176e5 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 1 May 2023 11:34:42 -0600 Subject: [PATCH 095/370] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index aeeef1bfd6..4baf2344c2 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "PowerSimulations" uuid = "e690365d-45e2-57bb-ac84-44ba829e73c4" authors = ["Jose Daniel Lara", "Clayton Barrows", "Daniel Thom", "Dheepak Krishnamurthy", "Sourabh Dalvi"] -version = "0.19.6" +version = "0.20.0" [deps] CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" From 055e20d2b7469293b9672585c19c1e312d81b4bb Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 1 May 2023 11:50:59 -0600 Subject: [PATCH 096/370] more readme corrections --- README.md | 4 ++-- docs/src/index.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5f8ed59fcb..e6aa29787b 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ julia> ] ## Usage -`PowerSimulations.jl` uses [PowerSystems.jl](https://github.com/NREL/PowerSystems.jl) to handle the data used in the simulations. +`PowerSimulations.jl` uses [PowerSystems.jl](https://github.com/NREL-Sienna/PowerSystems.jl) to handle the data used in the simulations. ```julia using PowerSimulations @@ -54,5 +54,5 @@ Contributions to the development and enhancement of PowerSimulations is welcome. ## License -PowerSimulations is released under a BSD [license](https://github.com/NREL/PowerSimulations.jl/blob/main/LICENSE). PowerSimulations has been developed as part of the Scalable Integrated Infrastructure Planning (SIIP) +PowerSimulations is released under a BSD [license](https://github.com/NREL-Sienna/PowerSimulations.jl/blob/main/LICENSE). PowerSimulations has been developed as part of the Scalable Integrated Infrastructure Planning (SIIP) initiative at the U.S. Department of Energy's National Renewable Energy Laboratory ([NREL](https://www.nrel.gov/)) diff --git a/docs/src/index.md b/docs/src/index.md index ba3418e5cf..6662f20c3f 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -29,7 +29,7 @@ The most common Simulation Model is the solution of a Unit Commitment and Econom `PowerSimulations.jl` is an active project under development, and we welcome your feedback, suggestions, and bug reports. -**Note**: `PowerSimulations.jl` uses the data model implemented in [`PowerSystems.jl`](https://github.com/NREL/PowerSystems.jl) +**Note**: `PowerSimulations.jl` uses the data model implemented in [`PowerSystems.jl`](https://github.com/NREL-Sienna/PowerSystems.jl) to construct optimization models. In most cases, you need to add `PowerSystems.jl` to your scripts. ## Installation From 0b26b1f6e919c65cbf4019e88d5249f97162c877 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 1 May 2023 11:53:56 -0600 Subject: [PATCH 097/370] update slack link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e6aa29787b..45b244a6fe 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![codecov](https://codecov.io/gh/NREL-Sienna/PowerSimulations.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/NREL-Sienna/PowerSimulations.jl) [![Documentation](https://github.com/NREL-Sienna/PowerSimulations.jl/workflows/Documentation/badge.svg)](https://nrel-sienna.github.io/PowerSimulations.jl/latest) [![DOI](https://zenodo.org/badge/109443246.svg)](https://zenodo.org/badge/latestdoi/109443246) -[](https://join.slack.com/t/nrel-siip/shared_invite/zt-glam9vdu-o8A9TwZTZqqNTKHa7q3BpQ) +[](https://join.slack.com/t/nrel-sienna/shared_invite/zt-glam9vdu-o8A9TwZTZqqNTKHa7q3BpQ) [![PowerSimulations Downloads](https://shields.io/endpoint?url=https://pkgs.genieframework.com/api/v1/badge/PowerSimulations)](https://pkgs.genieframework.com?packages=PowerSimulations) `PowerSimulations.jl` is a Julia package for power system modeling and simulation of Power Systems operations. The objectives of the package are: From 40f597afdc360b5d122792fee98d275c6d360c37 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 1 May 2023 12:12:20 -0600 Subject: [PATCH 098/370] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 45b244a6fe..bae459b92e 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![codecov](https://codecov.io/gh/NREL-Sienna/PowerSimulations.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/NREL-Sienna/PowerSimulations.jl) [![Documentation](https://github.com/NREL-Sienna/PowerSimulations.jl/workflows/Documentation/badge.svg)](https://nrel-sienna.github.io/PowerSimulations.jl/latest) [![DOI](https://zenodo.org/badge/109443246.svg)](https://zenodo.org/badge/latestdoi/109443246) -[](https://join.slack.com/t/nrel-sienna/shared_invite/zt-glam9vdu-o8A9TwZTZqqNTKHa7q3BpQ) +[](https://join.slack.com/t/nrel-sienna/shared_invite/zt-glam9vdu-o8A9TwZTZqqNTKHa7q3BpQ) [![PowerSimulations Downloads](https://shields.io/endpoint?url=https://pkgs.genieframework.com/api/v1/badge/PowerSimulations)](https://pkgs.genieframework.com?packages=PowerSimulations) `PowerSimulations.jl` is a Julia package for power system modeling and simulation of Power Systems operations. The objectives of the package are: From 92297b73a01d166cdb7cb9f0fe2e7328174ece83 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 2 May 2023 23:05:10 -0600 Subject: [PATCH 099/370] add branches to the device count --- src/core/optimization_container.jl | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index 786c27bfbc..e45e315f33 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -334,10 +334,16 @@ function init_optimization_container!( if get_horizon(settings) == UNSET_HORIZON set_horizon!(settings, PSY.get_forecast_horizon(sys)) end - - total_number_of_devices = length(get_available_components(PSY.Device, sys)) container.time_steps = 1:get_horizon(settings) + if T <: CopperPlatePowerModel || T <: AreaBalancePowerModel + total_number_of_devices = length(get_available_components(PSY.Device, sys)) + else + total_number_of_devices = length(get_available_components(PSY.Device, sys)) + total_number_of_devices += length(get_available_components(PSY.ACBranch, sys)) + end + + # The 10e6 limit is based on the sizes of the lp benchmark problems http://plato.asu.edu/ftp/lpcom.html # The maximum numbers of constraints and variables in the benchmark problems is 1,918,399 and 1,259,121, # respectively. See also https://prod-ng.sandia.gov/techlib-noauth/access-control.cgi/2013/138847.pdf @@ -345,7 +351,8 @@ function init_optimization_container!( if variable_count_estimate > 10e6 @warn( - "The estimated total number of variables that will be created in the model is $(variable_count_estimate). The total number of variables might be larger than 10e6 and could lead to large build or solve times." + "The lower estimate of total number of variables that will be created in the model is $(variable_count_estimate). \ + The total number of variables might be larger than 10e6 and could lead to large build or solve times." ) end From bda3558632e9d263b54d601120d8f442277573b3 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 2 May 2023 23:06:23 -0600 Subject: [PATCH 100/370] whitespace --- src/core/optimization_container.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index e45e315f33..5b69d35681 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -351,8 +351,7 @@ function init_optimization_container!( if variable_count_estimate > 10e6 @warn( - "The lower estimate of total number of variables that will be created in the model is $(variable_count_estimate). \ - The total number of variables might be larger than 10e6 and could lead to large build or solve times." + "The lower estimate of total number of variables that will be created in the model is $(variable_count_estimate). \The total number of variables might be larger than 10e6 and could lead to large build or solve times." ) end From 55415f84d87b4c63ce9d8b68a41d1e30c0432a71 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 3 May 2023 00:06:16 -0600 Subject: [PATCH 101/370] add option to pass a second filter function --- src/utils/powersystems_utils.jl | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/utils/powersystems_utils.jl b/src/utils/powersystems_utils.jl index 91b36dac16..22ff99377e 100644 --- a/src/utils/powersystems_utils.jl +++ b/src/utils/powersystems_utils.jl @@ -1,10 +1,23 @@ -function get_available_components(::Type{T}, sys::PSY.System) where {T <: PSY.Component} +function get_available_components( + ::Type{T}, + sys::PSY.System, + ::Nothing = nothing, +) where {T <: PSY.Component} return PSY.get_components(PSY.get_available, T, sys) end +function get_available_components( + ::Type{T}, + sys::PSY.System, + f::Function, +) where {T <: PSY.Component} + return f(PSY.get_components(PSY.get_available, T, sys)) +end + function get_available_components( ::Type{PSY.RegulationDevice{T}}, sys::PSY.System, + ::Nothing, ) where {T <: PSY.Component} return PSY.get_components( x -> (PSY.get_available(x) && PSY.has_service(x, PSY.AGC)), From 0aec11cb40f7e6aba2c46facdc909bc8cdc9b566 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 3 May 2023 00:06:27 -0600 Subject: [PATCH 102/370] message fix --- src/core/optimization_container.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index 5b69d35681..08130009f5 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -343,7 +343,6 @@ function init_optimization_container!( total_number_of_devices += length(get_available_components(PSY.ACBranch, sys)) end - # The 10e6 limit is based on the sizes of the lp benchmark problems http://plato.asu.edu/ftp/lpcom.html # The maximum numbers of constraints and variables in the benchmark problems is 1,918,399 and 1,259,121, # respectively. See also https://prod-ng.sandia.gov/techlib-noauth/access-control.cgi/2013/138847.pdf @@ -351,7 +350,8 @@ function init_optimization_container!( if variable_count_estimate > 10e6 @warn( - "The lower estimate of total number of variables that will be created in the model is $(variable_count_estimate). \The total number of variables might be larger than 10e6 and could lead to large build or solve times." + "The lower estimate of total number of variables that will be created in the model is $(variable_count_estimate). \\ + The total number of variables might be larger than 10e6 and could lead to large build or solve times." ) end From 85487e9fb7a0cc817354d137a7f13c6859e49395 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 3 May 2023 00:06:54 -0600 Subject: [PATCH 103/370] propagate filter to the device constructors --- .../device_constructors/branch_constructor.jl | 110 ++++++++++++------ .../constructor_validations.jl | 7 +- .../hydrogeneration_constructor.jl | 84 ++++++++----- .../device_constructors/load_constructor.jl | 36 ++++-- .../renewablegeneration_constructor.jl | 18 ++- .../thermalgeneration_constructor.jl | 87 +++++++++----- 6 files changed, 229 insertions(+), 113 deletions(-) diff --git a/src/devices_models/device_constructors/branch_constructor.jl b/src/devices_models/device_constructors/branch_constructor.jl index afa85f011f..e5cd948924 100644 --- a/src/devices_models/device_constructors/branch_constructor.jl +++ b/src/devices_models/device_constructors/branch_constructor.jl @@ -11,7 +11,8 @@ function construct_device!( }, ) where {T <: PSY.ACBranch} if has_subnetworks(network_model) - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(device_model, "filter_function")) add_variables!( container, FlowActivePowerVariable, @@ -42,7 +43,8 @@ function construct_device!( }, ) where {T <: PSY.ACBranch} if has_subnetworks(network_model) - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(device_model, "filter_function")) add_constraints!( container, RateLimitConstraint, @@ -66,7 +68,8 @@ function construct_device!( }, ) where {T <: PSY.ACBranch} if has_subnetworks(network_model) - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(device_model, "filter_function")) add_variables!( container, FlowActivePowerVariable, @@ -97,7 +100,8 @@ function construct_device!( }, ) where {T <: PSY.ACBranch} if has_subnetworks(network_model) - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(device_model, "filter_function")) branch_rate_bounds!(container, devices, device_model, S) end return @@ -114,7 +118,8 @@ function construct_device!( }, ) where {T <: PSY.ACBranch} if has_subnetworks(network_model) - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(device_model, "filter_function")) add_variables!( container, FlowActivePowerVariable, @@ -155,7 +160,8 @@ function construct_device!( network_model::NetworkModel{CopperPlatePowerModel}, ) where {T <: PSY.DCBranch} if has_subnetworks(network_model) - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(device_model, "filter_function")) add_variables!( container, FlowActivePowerVariable, @@ -183,7 +189,8 @@ function construct_device!( network_model::NetworkModel{CopperPlatePowerModel}, ) where {T <: PSY.DCBranch} if has_subnetworks(network_model) - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(device_model, "filter_function")) add_constraints!( container, FlowRateConstraint, @@ -231,7 +238,8 @@ function construct_device!( ) where {T <: PSY.ACBranch} @debug "construct_device" _group = LOG_GROUP_BRANCH_CONSTRUCTIONS - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(device_model, "filter_function")) add_constraints!(container, RateLimitConstraint, devices, device_model, network_model) add_constraint_dual!(container, sys, device_model) return @@ -242,10 +250,11 @@ function construct_device!( container::OptimizationContainer, sys::PSY.System, ::ArgumentConstructStage, - ::DeviceModel{T, StaticBranch}, + device_model::DeviceModel{T, StaticBranch}, network_model::NetworkModel{StandardPTDFModel}, ) where {T <: PSY.ACBranch} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(device_model, "filter_function")) add_variables!( container, FlowActivePowerVariable, @@ -263,7 +272,8 @@ function construct_device!( device_model::DeviceModel{T, StaticBranch}, network_model::NetworkModel{StandardPTDFModel}, ) where {T <: PSY.ACBranch} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(device_model, "filter_function")) add_constraints!(container, NetworkFlowConstraint, devices, device_model, network_model) add_constraints!(container, RateLimitConstraint, devices, device_model, network_model) add_constraint_dual!(container, sys, device_model) @@ -274,10 +284,11 @@ function construct_device!( container::OptimizationContainer, sys::PSY.System, ::ArgumentConstructStage, - ::DeviceModel{T, StaticBranchBounds}, + device_model::DeviceModel{T, StaticBranchBounds}, network_model::NetworkModel{StandardPTDFModel}, ) where {T <: PSY.ACBranch} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(device_model, "filter_function")) add_variables!( container, FlowActivePowerVariable, @@ -295,7 +306,8 @@ function construct_device!( device_model::DeviceModel{T, StaticBranchBounds}, network_model::NetworkModel{S}, ) where {T <: PSY.ACBranch, S <: StandardPTDFModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(device_model, "filter_function")) add_constraints!(container, NetworkFlowConstraint, devices, device_model, network_model) branch_rate_bounds!(container, devices, device_model, S) add_constraint_dual!(container, sys, device_model) @@ -306,10 +318,11 @@ function construct_device!( container::OptimizationContainer, sys::PSY.System, ::ArgumentConstructStage, - ::DeviceModel{T, StaticBranchUnbounded}, + device_model::DeviceModel{T, StaticBranchUnbounded}, network_model::NetworkModel{StandardPTDFModel}, ) where {T <: PSY.ACBranch} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(device_model, "filter_function")) add_variables!( container, FlowActivePowerVariable, @@ -327,7 +340,8 @@ function construct_device!( model::DeviceModel{T, StaticBranchUnbounded}, network_model::NetworkModel{StandardPTDFModel}, ) where {T <: PSY.ACBranch} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_constraints!(container, NetworkFlowConstraint, devices, model, network_model) add_constraint_dual!(container, sys, model) @@ -336,10 +350,10 @@ end # For AC Power only. Implements Bounds on the active power and rating constraints on the aparent power function construct_device!( - container::OptimizationContainer, - sys::PSY.System, + ::OptimizationContainer, + ::PSY.System, ::ArgumentConstructStage, - model::DeviceModel{T, StaticBranch}, + ::DeviceModel{T, StaticBranch}, ::NetworkModel{S}, ) where {T <: PSY.ACBranch, S <: PM.AbstractPowerModel} end @@ -350,7 +364,8 @@ function construct_device!( model::DeviceModel{T, StaticBranch}, network_model::NetworkModel{S}, ) where {T <: PSY.ACBranch, S <: PM.AbstractPowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) branch_rate_bounds!(container, devices, model, S) add_constraints!(container, RateLimitConstraintFromTo, devices, model, network_model) @@ -363,7 +378,7 @@ function construct_device!( container::OptimizationContainer, sys::PSY.System, ::ArgumentConstructStage, - model::DeviceModel{T, StaticBranchBounds}, + ::DeviceModel{T, StaticBranchBounds}, ::NetworkModel{S}, ) where {T <: PSY.ACBranch, S <: PM.AbstractPowerModel} end @@ -374,7 +389,8 @@ function construct_device!( model::DeviceModel{T, StaticBranchBounds}, ::NetworkModel{S}, ) where {T <: PSY.ACBranch, S <: PM.AbstractPowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) branch_rate_bounds!(container, devices, model, S) add_constraint_dual!(container, sys, model) return @@ -411,7 +427,8 @@ function construct_device!( U <: HVDCP2PUnbounded, S <: Union{StandardPTDFModel, PTDFPowerModel}, } - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_variables!(container, FlowActivePowerVariable, devices, U()) add_to_expression!( container, @@ -455,7 +472,8 @@ function construct_device!( model::DeviceModel{T, U}, network_model::NetworkModel{S}, ) where {T <: PSY.DCBranch, U <: HVDCP2PLossless, S <: PM.AbstractPowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_constraints!(container, FlowRateConstraint, devices, model, network_model) add_constraint_dual!(container, sys, model) return @@ -469,7 +487,8 @@ function construct_device!( model::DeviceModel{T, U}, network_model::NetworkModel{<:Union{StandardPTDFModel, PTDFPowerModel}}, ) where {T <: PSY.DCBranch, U <: HVDCP2PLossless} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_variables!(container, FlowActivePowerVariable, devices, U()) add_to_expression!( container, @@ -490,7 +509,8 @@ function construct_device!( model::DeviceModel{T, U}, network_model::NetworkModel{<:Union{StandardPTDFModel, PTDFPowerModel}}, ) where {T <: PSY.HVDCLine, U <: HVDCP2PLossless} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_constraints!(container, FlowRateConstraint, devices, model, network_model) add_constraint_dual!(container, sys, model) return @@ -503,7 +523,8 @@ function construct_device!( model::DeviceModel{PSY.HVDCLine, HVDCP2PDispatch}, network_model::NetworkModel{StandardPTDFModel}, ) - devices = get_available_components(PSY.HVDCLine, sys) + devices = + get_available_components(PSY.HVDCLine, sys, get_attribute(model, "filter_function")) add_variables!(container, FlowActivePowerToFromVariable, devices, HVDCP2PDispatch()) add_variables!(container, FlowActivePowerFromToVariable, devices, HVDCP2PDispatch()) add_variables!(container, HVDCLosses, devices, HVDCP2PDispatch()) @@ -542,7 +563,8 @@ function construct_device!( model::DeviceModel{PSY.HVDCLine, HVDCP2PDispatch}, network_model::NetworkModel{StandardPTDFModel}, ) - devices = get_available_components(PSY.HVDCLine, sys) + devices = + get_available_components(PSY.HVDCLine, sys, get_attribute(model, "filter_function")) add_constraints!(container, FlowRateConstraintFromTo, devices, model, network_model) add_constraints!(container, FlowRateConstraintToFrom, devices, model, network_model) add_constraints!(container, HVDCPowerBalance, devices, model, network_model) @@ -558,7 +580,8 @@ function construct_device!( model::DeviceModel{PSY.HVDCLine, HVDCP2PDispatch}, network_model::NetworkModel{T}, ) where {T <: PM.AbstractActivePowerModel} - devices = get_available_components(PSY.HVDCLine, sys) + devices = + get_available_components(PSY.HVDCLine, sys, get_attribute(model, "filter_function")) add_variables!(container, FlowActivePowerToFromVariable, devices, HVDCP2PDispatch()) add_variables!(container, FlowActivePowerFromToVariable, devices, HVDCP2PDispatch()) add_variables!(container, HVDCFlowDirectionVariable, devices, HVDCP2PDispatch()) @@ -588,7 +611,8 @@ function construct_device!( model::DeviceModel{PSY.HVDCLine, HVDCP2PDispatch}, network_model::NetworkModel{T}, ) where {T <: PM.AbstractActivePowerModel} - devices = get_available_components(PSY.HVDCLine, sys) + devices = + get_available_components(PSY.HVDCLine, sys, get_attribute(model, "filter_function")) add_constraints!(container, FlowRateConstraintFromTo, devices, model, network_model) add_constraints!(container, FlowRateConstraintToFrom, devices, model, network_model) add_constraints!(container, HVDCPowerBalance, devices, model, network_model) @@ -626,7 +650,11 @@ function construct_device!( model::DeviceModel{PSY.PhaseShiftingTransformer, PhaseAngleControl}, network_model::NetworkModel{PM.DCPPowerModel}, ) - devices = get_available_components(PSY.PhaseShiftingTransformer, sys) + devices = get_available_components( + PSY.PhaseShiftingTransformer, + sys, + get_attribute(model, "filter_function"), + ) add_variables!(container, FlowActivePowerVariable, devices, PhaseAngleControl()) add_variables!(container, PhaseShifterAngle, devices, PhaseAngleControl()) add_to_expression!( @@ -647,7 +675,11 @@ function construct_device!( model::DeviceModel{PSY.PhaseShiftingTransformer, PhaseAngleControl}, network_model::NetworkModel{StandardPTDFModel}, ) - devices = get_available_components(PSY.PhaseShiftingTransformer, sys) + devices = get_available_components( + PSY.PhaseShiftingTransformer, + sys, + get_attribute(model, "filter_function"), + ) add_variables!(container, FlowActivePowerVariable, devices, PhaseAngleControl()) add_variables!(container, PhaseShifterAngle, devices, PhaseAngleControl()) add_to_expression!( @@ -668,7 +700,11 @@ function construct_device!( model::DeviceModel{PSY.PhaseShiftingTransformer, PhaseAngleControl}, network_model::NetworkModel{PM.DCPPowerModel}, ) - devices = get_available_components(PSY.PhaseShiftingTransformer, sys) + devices = get_available_components( + PSY.PhaseShiftingTransformer, + sys, + get_attribute(model, "filter_function"), + ) add_constraints!(container, FlowLimitConstraint, devices, model, network_model) add_constraints!(container, PhaseAngleControlLimit, devices, model, network_model) add_constraints!(container, NetworkFlowConstraint, devices, model, network_model) @@ -683,7 +719,11 @@ function construct_device!( model::DeviceModel{PSY.PhaseShiftingTransformer, PhaseAngleControl}, network_model::NetworkModel{StandardPTDFModel}, ) - devices = get_available_components(PSY.PhaseShiftingTransformer, sys) + devices = get_available_components( + PSY.PhaseShiftingTransformer, + sys, + get_attribute(model, "filter_function"), + ) add_constraints!(container, FlowLimitConstraint, devices, model, network_model) add_constraints!(container, PhaseAngleControlLimit, devices, model, network_model) add_constraints!(container, NetworkFlowConstraint, devices, model, network_model) diff --git a/src/devices_models/device_constructors/constructor_validations.jl b/src/devices_models/device_constructors/constructor_validations.jl index d179729583..50fd4a3bff 100644 --- a/src/devices_models/device_constructors/constructor_validations.jl +++ b/src/devices_models/device_constructors/constructor_validations.jl @@ -1,8 +1,9 @@ function validate_available_devices( - device::DeviceModel{T, U}, - system, + device_model::DeviceModel{T, U}, + system::PSY.System, ) where {T <: PSY.Device, U <: AbstractDeviceFormulation} - devices = get_available_components(T, system) + devices = + get_available_components(T, system, get_attribute(device_model, "filter_function")) if isempty(devices) return false end diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index b27fb216ed..a2483f8e70 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -8,7 +8,8 @@ function construct_device!( model::DeviceModel{H, FixedOutput}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) @@ -52,7 +53,8 @@ function construct_device!( model::DeviceModel{H, FixedOutput}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) @@ -82,7 +84,8 @@ function construct_device!( D <: AbstractHydroDispatchFormulation, S <: PM.AbstractPowerModel, } - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, D()) add_variables!(container, ReactivePowerVariable, devices, D()) @@ -140,7 +143,8 @@ function construct_device!( D <: AbstractHydroDispatchFormulation, S <: PM.AbstractPowerModel, } - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -190,7 +194,8 @@ function construct_device!( D <: AbstractHydroDispatchFormulation, S <: PM.AbstractActivePowerModel, } - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, D()) add_variables!(container, EnergyOutput, devices, D()) @@ -238,7 +243,8 @@ function construct_device!( D <: AbstractHydroDispatchFormulation, S <: PM.AbstractActivePowerModel, } - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -275,7 +281,8 @@ function construct_device!( model::DeviceModel{H, HydroDispatchReservoirBudget}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirBudget()) add_variables!( @@ -332,7 +339,8 @@ function construct_device!( model::DeviceModel{H, HydroDispatchReservoirBudget}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -382,7 +390,8 @@ function construct_device!( model::DeviceModel{H, HydroDispatchReservoirBudget}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirBudget()) add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirBudget()) @@ -426,7 +435,8 @@ function construct_device!( model::DeviceModel{H, HydroDispatchReservoirBudget}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -466,7 +476,8 @@ function construct_device!( model::DeviceModel{H, HydroDispatchReservoirStorage}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirStorage()) add_variables!( @@ -543,7 +554,8 @@ function construct_device!( model::DeviceModel{H, HydroDispatchReservoirStorage}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -599,7 +611,8 @@ function construct_device!( model::DeviceModel{H, HydroDispatchReservoirStorage}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirStorage()) add_variables!(container, EnergyVariable, devices, HydroDispatchReservoirStorage()) @@ -665,7 +678,8 @@ function construct_device!( model::DeviceModel{H, HydroDispatchReservoirStorage}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -711,7 +725,8 @@ function construct_device!( model::DeviceModel{H, D}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, D()) add_variables!(container, ReactivePowerVariable, devices, D()) @@ -766,7 +781,8 @@ function construct_device!( model::DeviceModel{H, D}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -817,7 +833,8 @@ function construct_device!( D <: HydroCommitmentRunOfRiver, S <: PM.AbstractActivePowerModel, } - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, D()) add_variables!(container, OnVariable, devices, D()) @@ -866,7 +883,8 @@ function construct_device!( D <: HydroCommitmentRunOfRiver, S <: PM.AbstractActivePowerModel, } - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -903,7 +921,8 @@ function construct_device!( model::DeviceModel{H, D}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroGen, D <: HydroCommitmentReservoirBudget, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, D()) add_variables!(container, ReactivePowerVariable, devices, D()) @@ -957,7 +976,8 @@ function construct_device!( model::DeviceModel{H, D}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroGen, D <: HydroCommitmentReservoirBudget, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -1010,7 +1030,8 @@ function construct_device!( D <: HydroCommitmentReservoirBudget, S <: PM.AbstractActivePowerModel, } - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, D()) add_variables!(container, OnVariable, devices, D()) @@ -1059,7 +1080,8 @@ function construct_device!( D <: HydroCommitmentReservoirBudget, S <: PM.AbstractActivePowerModel, } - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -1099,7 +1121,8 @@ function construct_device!( model::DeviceModel{H, HydroCommitmentReservoirStorage}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_variables!( container, @@ -1183,7 +1206,8 @@ function construct_device!( model::DeviceModel{H, HydroCommitmentReservoirStorage}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -1239,7 +1263,8 @@ function construct_device!( model::DeviceModel{H, HydroCommitmentReservoirStorage}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_variables!( container, @@ -1309,7 +1334,8 @@ function construct_device!( model::DeviceModel{H, HydroCommitmentReservoirStorage}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -1357,7 +1383,8 @@ function construct_device!( model::DeviceModel{H, HydroDispatchPumpedStorage}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroPumpedStorage, S <: PM.AbstractActivePowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerInVariable, devices, HydroDispatchPumpedStorage()) add_variables!(container, ActivePowerOutVariable, devices, HydroDispatchPumpedStorage()) @@ -1410,7 +1437,8 @@ function construct_device!( model::DeviceModel{H, HydroDispatchPumpedStorage}, network_model::NetworkModel{S}, ) where {H <: PSY.HydroPumpedStorage, S <: PM.AbstractActivePowerModel} - devices = get_available_components(H, sys) + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) add_constraints!( container, diff --git a/src/devices_models/device_constructors/load_constructor.jl b/src/devices_models/device_constructors/load_constructor.jl index cc5b216637..61af8d4198 100644 --- a/src/devices_models/device_constructors/load_constructor.jl +++ b/src/devices_models/device_constructors/load_constructor.jl @@ -9,7 +9,8 @@ function construct_device!( D <: AbstractControllablePowerLoadFormulation, S <: PM.AbstractPowerModel, } - devices = get_available_components(L, sys) + devices = + get_available_components(L, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, D()) add_variables!(container, ReactivePowerVariable, devices, D()) @@ -50,7 +51,8 @@ function construct_device!( D <: AbstractControllablePowerLoadFormulation, S <: PM.AbstractPowerModel, } - devices = get_available_components(L, sys) + devices = + get_available_components(L, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -87,7 +89,8 @@ function construct_device!( D <: AbstractControllablePowerLoadFormulation, S <: PM.AbstractActivePowerModel, } - devices = get_available_components(L, sys) + devices = + get_available_components(L, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, D()) @@ -118,7 +121,8 @@ function construct_device!( D <: AbstractControllablePowerLoadFormulation, S <: PM.AbstractActivePowerModel, } - devices = get_available_components(L, sys) + devices = + get_available_components(L, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -143,7 +147,8 @@ function construct_device!( model::DeviceModel{L, PowerLoadInterruption}, network_model::NetworkModel{S}, ) where {L <: PSY.ControllableLoad, S <: PM.AbstractPowerModel} - devices = get_available_components(L, sys) + devices = + get_available_components(L, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, PowerLoadInterruption()) add_variables!(container, ReactivePowerVariable, devices, PowerLoadInterruption()) @@ -181,7 +186,8 @@ function construct_device!( model::DeviceModel{L, PowerLoadInterruption}, network_model::NetworkModel{S}, ) where {L <: PSY.ControllableLoad, S <: PM.AbstractPowerModel} - devices = get_available_components(L, sys) + devices = + get_available_components(L, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -214,7 +220,8 @@ function construct_device!( model::DeviceModel{L, PowerLoadInterruption}, network_model::NetworkModel{S}, ) where {L <: PSY.ControllableLoad, S <: PM.AbstractActivePowerModel} - devices = get_available_components(L, sys) + devices = + get_available_components(L, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, PowerLoadInterruption()) add_variables!(container, OnVariable, devices, PowerLoadInterruption()) @@ -242,7 +249,8 @@ function construct_device!( model::DeviceModel{L, PowerLoadInterruption}, network_model::NetworkModel{S}, ) where {L <: PSY.ControllableLoad, S <: PM.AbstractActivePowerModel} - devices = get_available_components(L, sys) + devices = + get_available_components(L, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -267,7 +275,8 @@ function construct_device!( model::DeviceModel{L, StaticPowerLoad}, network_model::NetworkModel{S}, ) where {L <: PSY.ElectricLoad, S <: PM.AbstractPowerModel} - devices = get_available_components(L, sys) + devices = + get_available_components(L, sys, get_attribute(model, "filter_function")) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) @@ -298,7 +307,8 @@ function construct_device!( model::DeviceModel{L, StaticPowerLoad}, network_model::NetworkModel{S}, ) where {L <: PSY.ElectricLoad, S <: PM.AbstractActivePowerModel} - devices = get_available_components(L, sys) + devices = + get_available_components(L, sys, get_attribute(model, "filter_function")) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) @@ -336,7 +346,8 @@ function construct_device!( D <: AbstractControllablePowerLoadFormulation, S <: PM.AbstractPowerModel, } - devices = get_available_components(L, sys) + devices = + get_available_components(L, sys, get_attribute(model, "filter_function")) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) @@ -371,7 +382,8 @@ function construct_device!( D <: AbstractControllablePowerLoadFormulation, S <: PM.AbstractActivePowerModel, } - devices = get_available_components(L, sys) + devices = + get_available_components(L, sys, get_attribute(model, "filter_function")) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) add_to_expression!( diff --git a/src/devices_models/device_constructors/renewablegeneration_constructor.jl b/src/devices_models/device_constructors/renewablegeneration_constructor.jl index 29f4c5be26..c023629aa3 100644 --- a/src/devices_models/device_constructors/renewablegeneration_constructor.jl +++ b/src/devices_models/device_constructors/renewablegeneration_constructor.jl @@ -9,7 +9,8 @@ function construct_device!( D <: AbstractRenewableDispatchFormulation, S <: PM.AbstractPowerModel, } - devices = get_available_components(R, sys) + devices = + get_available_components(R, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, D()) add_variables!(container, ReactivePowerVariable, devices, D()) @@ -66,7 +67,8 @@ function construct_device!( D <: AbstractRenewableDispatchFormulation, S <: PM.AbstractPowerModel, } - devices = get_available_components(R, sys) + devices = + get_available_components(R, sys, get_attribute(model, "filter_function")) if has_service_model(model) add_constraints!( @@ -115,7 +117,8 @@ function construct_device!( D <: AbstractRenewableDispatchFormulation, S <: PM.AbstractActivePowerModel, } - devices = get_available_components(R, sys) + devices = + get_available_components(R, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, D()) @@ -163,7 +166,8 @@ function construct_device!( D <: AbstractRenewableDispatchFormulation, S <: PM.AbstractActivePowerModel, } - devices = get_available_components(R, sys) + devices = + get_available_components(R, sys, get_attribute(model, "filter_function")) if has_service_model(model) add_constraints!( @@ -200,7 +204,8 @@ function construct_device!( model::DeviceModel{R, FixedOutput}, network_model::NetworkModel{S}, ) where {R <: PSY.RenewableGen, S <: PM.AbstractPowerModel} - devices = get_available_components(R, sys) + devices = + get_available_components(R, sys, get_attribute(model, "filter_function")) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) @@ -231,7 +236,8 @@ function construct_device!( model::DeviceModel{R, FixedOutput}, network_model::NetworkModel{S}, ) where {R <: PSY.RenewableGen, S <: PM.AbstractActivePowerModel} - devices = get_available_components(R, sys) + devices = + get_available_components(R, sys, get_attribute(model, "filter_function")) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) add_to_expression!( diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 347262beb8..06a3dee262 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -5,7 +5,8 @@ function construct_device!( ::DeviceModel{T, FixedOutput}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractActivePowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) add_to_expression!( container, @@ -44,7 +45,8 @@ function construct_device!( D <: AbstractStandardUnitCommitment, S <: PM.AbstractPowerModel, } - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, D()) add_variables!(container, ReactivePowerVariable, devices, D()) @@ -110,7 +112,8 @@ function construct_device!( D <: AbstractStandardUnitCommitment, S <: PM.AbstractPowerModel, } - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -161,7 +164,8 @@ function construct_device!( D <: AbstractStandardUnitCommitment, S <: PM.AbstractActivePowerModel, } - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, D()) add_variables!(container, OnVariable, devices, D()) @@ -219,7 +223,8 @@ function construct_device!( D <: AbstractStandardUnitCommitment, S <: PM.AbstractActivePowerModel, } - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_constraints!( container, ActivePowerVariableLimitsConstraint, @@ -259,7 +264,8 @@ function construct_device!( model::DeviceModel{T, ThermalBasicUnitCommitment}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractPowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, ThermalBasicUnitCommitment()) add_variables!(container, ReactivePowerVariable, devices, ThermalBasicUnitCommitment()) @@ -319,7 +325,8 @@ function construct_device!( model::DeviceModel{T, ThermalBasicUnitCommitment}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractPowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -365,7 +372,8 @@ function construct_device!( model::DeviceModel{T, ThermalBasicUnitCommitment}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractActivePowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, ThermalBasicUnitCommitment()) add_variables!(container, OnVariable, devices, ThermalBasicUnitCommitment()) @@ -416,7 +424,8 @@ function construct_device!( model::DeviceModel{T, ThermalBasicUnitCommitment}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractActivePowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -454,7 +463,8 @@ function construct_device!( model::DeviceModel{T, ThermalStandardDispatch}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractPowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, ThermalStandardDispatch()) add_variables!(container, ReactivePowerVariable, devices, ThermalStandardDispatch()) @@ -511,7 +521,8 @@ function construct_device!( model::DeviceModel{T, ThermalStandardDispatch}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractPowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -557,7 +568,8 @@ function construct_device!( model::DeviceModel{T, ThermalStandardDispatch}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractActivePowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, ThermalStandardDispatch()) @@ -605,7 +617,8 @@ function construct_device!( model::DeviceModel{T, ThermalStandardDispatch}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractActivePowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -644,7 +657,8 @@ function construct_device!( D <: AbstractThermalDispatchFormulation, S <: PM.AbstractPowerModel, } - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, D()) add_variables!(container, ReactivePowerVariable, devices, D()) @@ -700,7 +714,8 @@ function construct_device!( D <: AbstractThermalDispatchFormulation, S <: PM.AbstractPowerModel, } - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -746,7 +761,8 @@ function construct_device!( D <: AbstractThermalDispatchFormulation, S <: PM.AbstractActivePowerModel, } - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_variables!(container, ActivePowerVariable, devices, D()) @@ -793,7 +809,8 @@ function construct_device!( D <: AbstractThermalDispatchFormulation, S <: PM.AbstractActivePowerModel, } - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -1091,7 +1108,8 @@ function construct_device!( model::DeviceModel{T, ThermalCompactUnitCommitment}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractPowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_variables!( container, @@ -1162,7 +1180,8 @@ function construct_device!( model::DeviceModel{T, ThermalCompactUnitCommitment}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractPowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -1207,7 +1226,8 @@ function construct_device!( model::DeviceModel{T, ThermalCompactUnitCommitment}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractActivePowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_variables!( container, @@ -1271,7 +1291,8 @@ function construct_device!( model::DeviceModel{T, ThermalCompactUnitCommitment}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractActivePowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -1308,7 +1329,8 @@ function construct_device!( model::DeviceModel{T, ThermalBasicCompactUnitCommitment}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractPowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_variables!( container, @@ -1377,7 +1399,8 @@ function construct_device!( model::DeviceModel{T, ThermalBasicCompactUnitCommitment}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractPowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -1420,7 +1443,8 @@ function construct_device!( model::DeviceModel{T, ThermalBasicCompactUnitCommitment}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractActivePowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_variables!( container, @@ -1482,7 +1506,8 @@ function construct_device!( model::DeviceModel{T, ThermalBasicCompactUnitCommitment}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractActivePowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -1517,7 +1542,8 @@ function construct_device!( model::DeviceModel{T, ThermalCompactDispatch}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractPowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_variables!(container, PowerAboveMinimumVariable, devices, ThermalCompactDispatch()) add_variables!(container, ReactivePowerVariable, devices, ThermalCompactDispatch()) @@ -1599,7 +1625,8 @@ function construct_device!( model::DeviceModel{T, ThermalCompactDispatch}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractPowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_constraints!( container, @@ -1642,7 +1669,8 @@ function construct_device!( model::DeviceModel{T, ThermalCompactDispatch}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractActivePowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_variables!(container, PowerAboveMinimumVariable, devices, ThermalCompactDispatch()) @@ -1700,7 +1728,8 @@ function construct_device!( model::DeviceModel{T, ThermalCompactDispatch}, network_model::NetworkModel{S}, ) where {T <: PSY.ThermalGen, S <: PM.AbstractActivePowerModel} - devices = get_available_components(T, sys) + devices = + get_available_components(T, sys, get_attribute(model, "filter_function")) add_constraints!( container, From 005c9ad4ac2208fe0261fd1a1c726b5d4427c350 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 3 May 2023 00:07:08 -0600 Subject: [PATCH 104/370] apply filter in other places --- .../devices/common/add_constraint_dual.jl | 9 ++++--- .../devices/hydro_generation.jl | 26 +++---------------- src/network_models/pm_translator.jl | 7 ++--- src/parameters/update_parameters.jl | 15 ++++++++--- 4 files changed, 24 insertions(+), 33 deletions(-) diff --git a/src/devices_models/devices/common/add_constraint_dual.jl b/src/devices_models/devices/common/add_constraint_dual.jl index 592a99db30..78d90b98b1 100644 --- a/src/devices_models/devices/common/add_constraint_dual.jl +++ b/src/devices_models/devices/common/add_constraint_dual.jl @@ -1,11 +1,12 @@ function add_constraint_dual!( container::OptimizationContainer, sys::PSY.System, - model::DeviceModel{T, D}, + device_model::DeviceModel{T, D}, ) where {T <: PSY.Component, D <: AbstractDeviceFormulation} - if !isempty(get_duals(model)) - devices = get_available_components(T, sys) - for constraint_type in get_duals(model) + if !isempty(get_duals(device_model)) + devices = + get_available_components(T, sys, get_attribute(device_model, "filter_function")) + for constraint_type in get_duals(device_model) assign_dual_variable!(container, constraint_type, devices, D) end end diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index ce935d0325..80e4fcd131 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -707,34 +707,14 @@ function calculate_aux_variable_value!( ::AuxVarKey{EnergyOutput, T}, system::PSY.System, ) where {T <: PSY.HydroGen} - devices = get_available_components(T, system) - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR p_variable_results = get_variable(container, ActivePowerVariable(), T) - aux_variable_container = get_aux_variable(container, EnergyOutput(), T) - for d in devices, t in time_steps - name = PSY.get_name(d) - aux_variable_container[name, t] = - jump_value(p_variable_results[name, t]) * fraction_of_hour - end - - return -end - -function calculate_aux_variable_value!( - container::OptimizationContainer, - ::AuxVarKey{EnergyOutput, T}, - system::PSY.System, -) where {T <: PSY.HydroPumpedStorage} - devices = get_available_components(T, system) + devices = axes(p_variable_results, 1) time_steps = get_time_steps(container) resolution = get_resolution(container) fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - p_variable_results = get_variable(container, ActivePowerOutVariable(), T) + p_variable_results = get_variable(container, ActivePowerVariable(), T) aux_variable_container = get_aux_variable(container, EnergyOutput(), T) - for d in devices, t in time_steps - name = PSY.get_name(d) + for name in devices, t in time_steps aux_variable_container[name, t] = jump_value(p_variable_results[name, t]) * fraction_of_hour end diff --git a/src/network_models/pm_translator.jl b/src/network_models/pm_translator.jl index e4802543d9..5d52f160d1 100644 --- a/src/network_models/pm_translator.jl +++ b/src/network_models/pm_translator.jl @@ -382,10 +382,11 @@ function get_branches_to_pm( PMmap_br = Dict{PM_MAP_TUPLE, T}() for (d, device_model) in branch_template - !(get_component_type(device_model) <: T) && continue + comp_type = get_component_type(device_model) + !(comp_type <: T) && continue start_idx += length(PM_branches) - for (i, branch) in - enumerate(get_available_components(get_component_type(device_model), sys)) + filter_func = get_attribute(device_model, "filter_function") + for (i, branch) in enumerate(get_available_components(comp_type, sys, filter_func)) ix = i + start_idx PM_branches["$(ix)"] = get_branch_to_pm(ix, branch, get_formulation(device_model), S) diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index a49966652e..6a01c8b4e7 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -62,7 +62,10 @@ function _update_parameter_values!( horizon = get_time_steps(get_optimization_container(model))[end] ts_name = get_time_series_name(attributes) multiplier_id = get_time_series_multiplier_id(attributes) - components = get_available_components(V, get_system(model)) + template = get_template(model) + device_model = get_model(template, V) + filter_func = get_attribute(device_model, "filter_function") + components = get_available_components(V, get_system(model), filter_func) ts_uuids = Set{String}() for component in components ts_uuid = get_time_series_uuid(U, component, ts_name) @@ -129,7 +132,10 @@ function _update_parameter_values!( ::DatasetContainer{DataFrameDataset}, ) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.SingleTimeSeries, V <: PSY.Device} initial_forecast_time = get_current_time(model) - components = get_available_components(V, get_system(model)) + template = get_template(model) + device_model = get_model(template, V) + filter_func = get_attribute(device_model, "filter_function") + components = get_available_components(V, get_system(model), filter_func) ts_name = get_time_series_name(attributes) ts_uuids = Set{String}() for component in components @@ -573,7 +579,10 @@ function _update_parameter_values!( horizon = time_steps[end] container = get_optimization_container(model) @assert !is_synchronized(container) - components = get_available_components(V, get_system(model)) + template = get_template(model) + device_model = get_model(template, V) + filter_func = get_attribute(device_model, "filter_function") + components = get_available_components(V, get_system(model), filter_func) for component in components if _has_variable_cost_parameter(component) From c3313600a25dda021ed7493a75879372d839d13e Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 3 May 2023 09:32:45 -0600 Subject: [PATCH 105/370] add test and check --- src/utils/powersystems_utils.jl | 2 +- test/test_model_decision.jl | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/utils/powersystems_utils.jl b/src/utils/powersystems_utils.jl index 22ff99377e..c0a7c97120 100644 --- a/src/utils/powersystems_utils.jl +++ b/src/utils/powersystems_utils.jl @@ -11,7 +11,7 @@ function get_available_components( sys::PSY.System, f::Function, ) where {T <: PSY.Component} - return f(PSY.get_components(PSY.get_available, T, sys)) + return PSY.get_components(x -> PSY.get_available(x) && f(x), T, sys) end function get_available_components( diff --git a/test/test_model_decision.jl b/test/test_model_decision.jl index 15750d6f35..c2d4299938 100644 --- a/test/test_model_decision.jl +++ b/test/test_model_decision.jl @@ -649,3 +649,34 @@ end # We only test this field because most free solvers don't support detailed stats @test !ismissing(get_optimizer_stats(UC).objective_bound) end + +@testset "Test filter function atttribute" begin + c_sys5 = PSB.build_system(PSITestSystems, "c_sys5") + template = get_thermal_standard_uc_template() + new_model = DeviceModel( + ThermalStandard, + ThermalBasicUnitCommitment; + attributes = Dict("filter_function" => x -> PSY.get_name(x) != "Alta"), + ) + set_device_model!(template, new_model) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "test"), + ) + UC = DecisionModel( + template, + c_sys5; + optimizer = GLPK_optimizer, + detailed_optimizer_stats = true, + ) + output_dir = mktempdir(; cleanup = true) + @test build!(UC; output_dir = output_dir) == PSI.BuildStatus.BUILT + @test solve!(UC) == RunStatus.SUCCESSFUL + # We only test this field because most free solvers don't support detailed stats + p_variable = PSI.get_variable( + PSI.get_optimization_container(UC), + ActivePowerVariable(), + ThermalStandard, + ) + @test "Alta" ∉ axes(p_variable, 1) +end From b7da2e790fb7dab09b9991ac91b305ff17f7c7a4 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 4 May 2023 10:28:17 -0600 Subject: [PATCH 106/370] add fix --- .../devices/hydro_generation.jl | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 80e4fcd131..6e8ec34c84 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -701,11 +701,11 @@ function add_constraints!( end ##################################### Auxillary Variables ############################ - -function calculate_aux_variable_value!( +function _calculate_aux_variable_value!( container::OptimizationContainer, ::AuxVarKey{EnergyOutput, T}, system::PSY.System, + p_variable_results::JuMPVariableArray, ) where {T <: PSY.HydroGen} p_variable_results = get_variable(container, ActivePowerVariable(), T) devices = axes(p_variable_results, 1) @@ -722,6 +722,36 @@ function calculate_aux_variable_value!( return end +function calculate_aux_variable_value!( + container::OptimizationContainer, + ::AuxVarKey{EnergyOutput, T}, + system::PSY.System, +) where {T <: PSY.HydroGen} + p_variable_results = get_variable(container, ActivePowerVariable(), T) + _calculate_aux_variable_value!( + container, + ::AuxVarKey{EnergyOutput, T}, + system, + p_variable_results, + ) + return +end + +function calculate_aux_variable_value!( + container::OptimizationContainer, + ::AuxVarKey{EnergyOutput, T}, + system::PSY.System, +) where {T <: PSY.HydroPumpedStorage} + p_variable_results = get_variable(container, ActivePowerOutVariable(), T) + _calculate_aux_variable_value!( + container, + ::AuxVarKey{EnergyOutput, T}, + system, + p_variable_results, + ) + return +end + ##################################### Hydro generation cost ############################ function objective_function!( container::OptimizationContainer, From d8442dde4448130f63df63e31cef59eccf616014 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 4 May 2023 11:03:39 -0600 Subject: [PATCH 107/370] fix error --- src/devices_models/devices/hydro_generation.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 6e8ec34c84..d2e6af03bd 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -724,13 +724,13 @@ end function calculate_aux_variable_value!( container::OptimizationContainer, - ::AuxVarKey{EnergyOutput, T}, + aux_key::AuxVarKey{EnergyOutput, T}, system::PSY.System, ) where {T <: PSY.HydroGen} p_variable_results = get_variable(container, ActivePowerVariable(), T) _calculate_aux_variable_value!( container, - ::AuxVarKey{EnergyOutput, T}, + aux_key, system, p_variable_results, ) @@ -739,13 +739,13 @@ end function calculate_aux_variable_value!( container::OptimizationContainer, - ::AuxVarKey{EnergyOutput, T}, + aux_key::AuxVarKey{EnergyOutput, T}, system::PSY.System, ) where {T <: PSY.HydroPumpedStorage} p_variable_results = get_variable(container, ActivePowerOutVariable(), T) _calculate_aux_variable_value!( container, - ::AuxVarKey{EnergyOutput, T}, + aux_key, system, p_variable_results, ) From a00cba436aa7c6facdd6c422fc9e02307aa1f1e8 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 4 May 2023 11:25:43 -0600 Subject: [PATCH 108/370] remove variable overwrite --- src/devices_models/devices/hydro_generation.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index d2e6af03bd..65792bb3bf 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -707,12 +707,10 @@ function _calculate_aux_variable_value!( system::PSY.System, p_variable_results::JuMPVariableArray, ) where {T <: PSY.HydroGen} - p_variable_results = get_variable(container, ActivePowerVariable(), T) devices = axes(p_variable_results, 1) time_steps = get_time_steps(container) resolution = get_resolution(container) fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - p_variable_results = get_variable(container, ActivePowerVariable(), T) aux_variable_container = get_aux_variable(container, EnergyOutput(), T) for name in devices, t in time_steps aux_variable_container[name, t] = From cde35a3924b01ecff6ea86c4d539bf70af112c6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20Henr=C3=ADquez-Auba?= Date: Thu, 4 May 2023 12:34:42 -0700 Subject: [PATCH 109/370] Add reserves down for renewable dispatch (#971) * add constructor * add range constraints --- .../renewablegeneration_constructor.jl | 16 +++++++++++ .../devices/renewable_generation.jl | 27 +++++++++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/devices_models/device_constructors/renewablegeneration_constructor.jl b/src/devices_models/device_constructors/renewablegeneration_constructor.jl index c023629aa3..34a8edd469 100644 --- a/src/devices_models/device_constructors/renewablegeneration_constructor.jl +++ b/src/devices_models/device_constructors/renewablegeneration_constructor.jl @@ -71,6 +71,14 @@ function construct_device!( get_available_components(R, sys, get_attribute(model, "filter_function")) if has_service_model(model) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) add_constraints!( container, ActivePowerVariableLimitsConstraint, @@ -170,6 +178,14 @@ function construct_device!( get_available_components(R, sys, get_attribute(model, "filter_function")) if has_service_model(model) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) add_constraints!( container, ActivePowerVariableLimitsConstraint, diff --git a/src/devices_models/devices/renewable_generation.jl b/src/devices_models/devices/renewable_generation.jl index c753ac0b04..6d50950544 100644 --- a/src/devices_models/devices/renewable_generation.jl +++ b/src/devices_models/devices/renewable_generation.jl @@ -5,7 +5,7 @@ get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.Renew ########################### ActivePowerVariable, RenewableGen ################################# get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.RenewableGen}, ::AbstractRenewableFormulation) = false - +get_min_max_limits(d::PSY.RenewableGen, ::Type{ActivePowerVariableLimitsConstraint}, ::Type{<:AbstractRenewableFormulation}) = (min = 0.0, max = PSY.get_max_active_power(d)) get_variable_lower_bound(::ActivePowerVariable, d::PSY.RenewableGen, ::AbstractRenewableFormulation) = 0.0 get_variable_upper_bound(::ActivePowerVariable, d::PSY.RenewableGen, ::AbstractRenewableFormulation) = PSY.get_max_active_power(d) @@ -106,7 +106,7 @@ end function add_constraints!( container::OptimizationContainer, T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, + U::Type{<:Union{VariableType, ActivePowerRangeExpressionUB}}, devices::IS.FlattenIteratorWrapper{V}, model::DeviceModel{V, W}, ::NetworkModel{X}, @@ -127,6 +127,29 @@ function add_constraints!( return end +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{ActivePowerRangeExpressionLB}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where { + V <: PSY.RenewableGen, + W <: AbstractRenewableDispatchFormulation, + X <: PM.AbstractPowerModel, +} + add_range_constraints!( + container, + T, + U, + devices, + model, + X, + ) + return +end + ##################################### renewable generation cost ############################ function objective_function!( container::OptimizationContainer, From 87c61f892b4044a8d87b1186fdd16bba2652f71a Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 5 May 2023 15:35:32 -0600 Subject: [PATCH 110/370] add fix to handle cases with isolated buses (#972) --- src/devices_models/devices/common/add_to_expression.jl | 4 ++-- test/test_services_constructor.jl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 8b6cf918cc..20e6a6fca9 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -889,8 +889,8 @@ function add_to_expression!( } variable = get_variable(container, U(), PSY.Bus) expression = get_expression(container, T(), PSY.Bus) - bus_numbers = PSY.get_number.(PSY.get_components(PSY.Bus, sys)) - for t in get_time_steps(container), n in bus_numbers + @assert_op length(axes(variable, 1)) == length(axes(expression, 1)) + for t in get_time_steps(container), n in axes(variable, 1) _add_to_jump_expression!( expression[n, t], variable[n, t], diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index 4fd3a477a1..9c4100a19c 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -129,7 +129,7 @@ end c_sys5_re = PSB.build_system(PSITestSystems, "c_sys5_re"; add_reserves = true) model = DecisionModel(template, c_sys5_re) @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 360, 0, 72, 48, 72, false) + moi_tests(model, 360, 0, 72, 120, 72, false) end @testset "Test Reserves from Hydro" begin From 6dec66bc622e1a9878c40e915be0108c98da5b85 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 5 May 2023 15:37:38 -0600 Subject: [PATCH 111/370] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 4baf2344c2..8858201909 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "PowerSimulations" uuid = "e690365d-45e2-57bb-ac84-44ba829e73c4" authors = ["Jose Daniel Lara", "Clayton Barrows", "Daniel Thom", "Dheepak Krishnamurthy", "Sourabh Dalvi"] -version = "0.20.0" +version = "0.20.1" [deps] CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" From 78221e5541026f51bfe210fb044ef87fde1cf2f2 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 8 May 2023 23:08:12 -0600 Subject: [PATCH 112/370] change pm filter --- src/network_models/pm_translator.jl | 26 ++++++++++++++------------ src/utils/powersystems_utils.jl | 8 ++++++++ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/network_models/pm_translator.jl b/src/network_models/pm_translator.jl index 5d52f160d1..329dd457ab 100644 --- a/src/network_models/pm_translator.jl +++ b/src/network_models/pm_translator.jl @@ -1,6 +1,15 @@ const PM_MAP_TUPLE = NamedTuple{(:from_to, :to_from), Tuple{Tuple{Int, Int, Int}, Tuple{Int, Int, Int}}} + +const PM_BUSTYPES = Dict{PSY.BusTypes, Int}( + PSY.BusTypes.ISOLATED => 4, + PSY.BusTypes.PQ => 1, + PSY.BusTypes.PV => 2, + PSY.BusTypes.REF => 3, + PSY.BusTypes.SLACK => 3, +) + struct PMmap bus::Dict{Int, PSY.Bus} arcs::Dict{PM_MAP_TUPLE, <:PSY.ACBranch} @@ -416,20 +425,15 @@ function get_buses_to_pm(buses::IS.FlattenIteratorWrapper{PSY.Bus}) PM_buses = Dict{String, Any}() PMmap_buses = Dict{Int, PSY.Bus}() - pm_bustypes = Dict{PSY.BusTypes, Int}( - PSY.BusTypes.ISOLATED => 4, - PSY.BusTypes.PQ => 1, - PSY.BusTypes.PV => 2, - PSY.BusTypes.REF => 3, - PSY.BusTypes.SLACK => 3, - ) - for bus in buses + if PSY.get_bustype(bus) != PSY.BusTypes.ISOLATED::PSY.BusTypes + continue + end number = PSY.get_number(bus) PM_bus = Dict{String, Any}( "zone" => 1, "bus_i" => number, - "bus_type" => pm_bustypes[PSY.get_bustype(bus)], + "bus_type" => PM_BUSTYPES[PSY.get_bustype(bus)], "vmax" => PSY.get_voltage_limits(bus).max, "area" => 1, "vmin" => PSY.get_voltage_limits(bus).min, @@ -442,9 +446,7 @@ function get_buses_to_pm(buses::IS.FlattenIteratorWrapper{PSY.Bus}) "name" => PSY.get_name(bus), ) PM_buses["$(number)"] = PM_bus - if PSY.get_bustype(bus) != PSY.BusTypes.ISOLATED::PSY.BusTypes - PMmap_buses[number] = bus - end + PMmap_buses[number] = bus end return PM_buses, PMmap_buses end diff --git a/src/utils/powersystems_utils.jl b/src/utils/powersystems_utils.jl index c0a7c97120..d7303f214f 100644 --- a/src/utils/powersystems_utils.jl +++ b/src/utils/powersystems_utils.jl @@ -14,6 +14,14 @@ function get_available_components( return PSY.get_components(x -> PSY.get_available(x) && f(x), T, sys) end +function get_available_components( + ::Type{PSY.Bus}, + sys::PSY.System, + ::Nothing = nothing, +) + return PSY.get_components(x -> PSY.get_bustype(x) != PSY.BusTypes.ISOLATED, PSY.Bus, sys) +end + function get_available_components( ::Type{PSY.RegulationDevice{T}}, sys::PSY.System, From 8dbb9a61dd9f9a4d4751407a5c999060fbbee62a Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 8 May 2023 23:11:06 -0600 Subject: [PATCH 113/370] add conditional at the top --- src/network_models/pm_translator.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network_models/pm_translator.jl b/src/network_models/pm_translator.jl index 329dd457ab..a699550774 100644 --- a/src/network_models/pm_translator.jl +++ b/src/network_models/pm_translator.jl @@ -426,7 +426,7 @@ function get_buses_to_pm(buses::IS.FlattenIteratorWrapper{PSY.Bus}) PMmap_buses = Dict{Int, PSY.Bus}() for bus in buses - if PSY.get_bustype(bus) != PSY.BusTypes.ISOLATED::PSY.BusTypes + if PSY.get_bustype(bus) == PSY.BusTypes.ISOLATED continue end number = PSY.get_number(bus) From 9f7426ac2350166626f770892ba4fe6afa3e9c5c Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 11 May 2023 17:15:56 -0600 Subject: [PATCH 114/370] use get_available components --- src/core/network_model.jl | 2 +- src/devices_models/devices/common/add_constraint_dual.jl | 2 +- src/devices_models/devices/common/add_to_expression.jl | 4 ++-- src/network_models/network_slack_variables.jl | 4 ++-- src/network_models/pm_translator.jl | 2 +- src/network_models/powermodels_interface.jl | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/core/network_model.jl b/src/core/network_model.jl index 7003144ef4..c6217c938d 100644 --- a/src/core/network_model.jl +++ b/src/core/network_model.jl @@ -113,7 +113,7 @@ function _assign_subnetworks_to_buses( ) where {T <: Union{CopperPlatePowerModel, StandardPTDFModel}} subnetworks = model.subnetworks temp_bus_map = Dict{Int, Int}() - for bus in PSY.get_components(PSY.Bus, sys) + for bus in PSY.get_available_components(PSY.Bus, sys) bus_no = PSY.get_number(bus) if haskey(temp_bus_map, bus_no) model.bus_area_map[bus] = temp_bus_map[bus_no] diff --git a/src/devices_models/devices/common/add_constraint_dual.jl b/src/devices_models/devices/common/add_constraint_dual.jl index 78d90b98b1..5c5f5a1e5c 100644 --- a/src/devices_models/devices/common/add_constraint_dual.jl +++ b/src/devices_models/devices/common/add_constraint_dual.jl @@ -19,7 +19,7 @@ function add_constraint_dual!( model::NetworkModel{T}, ) where {T <: PM.AbstractPowerModel} if !isempty(get_duals(model)) - devices = PSY.get_components(PSY.Bus, sys) + devices = PSY.get_available_components(PSY.Bus, sys) for constraint_type in get_duals(model) assign_dual_variable!(container, constraint_type, devices, model) end diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 20e6a6fca9..9894d82bb4 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -913,7 +913,7 @@ function add_to_expression!( } variable = get_variable(container, U(), PSY.Bus, "P") expression = get_expression(container, T(), PSY.Bus) - bus_numbers = PSY.get_number.(PSY.get_components(PSY.Bus, sys)) + bus_numbers = PSY.get_number.(PSY.get_available_components(PSY.Bus, sys)) for t in get_time_steps(container), n in bus_numbers _add_to_jump_expression!( expression[n, t], @@ -937,7 +937,7 @@ function add_to_expression!( } variable = get_variable(container, U(), PSY.Bus, "Q") expression = get_expression(container, T(), PSY.Bus) - bus_numbers = PSY.get_number.(PSY.get_components(PSY.Bus, sys)) + bus_numbers = PSY.get_number.(PSY.get_available_components(PSY.Bus, sys)) for t in get_time_steps(container), n in bus_numbers _add_to_jump_expression!( expression[n, t], diff --git a/src/network_models/network_slack_variables.jl b/src/network_models/network_slack_variables.jl index 8cf22bdb33..d29d673d1a 100644 --- a/src/network_models/network_slack_variables.jl +++ b/src/network_models/network_slack_variables.jl @@ -37,7 +37,7 @@ function add_variables!( U <: PM.AbstractActivePowerModel, } time_steps = get_time_steps(container) - bus_numbers = PSY.get_number.(PSY.get_components(PSY.Bus, sys)) + bus_numbers = PSY.get_number.(PSY.get_available_components(PSY.Bus, sys)) variable = add_variable_container!(container, T(), PSY.Bus, bus_numbers, time_steps) for t in time_steps, n in bus_numbers @@ -60,7 +60,7 @@ function add_variables!( U <: PM.AbstractPowerModel, } time_steps = get_time_steps(container) - bus_numbers = PSY.get_number.(PSY.get_components(PSY.Bus, sys)) + bus_numbers = PSY.get_number.(PSY.get_available_components(PSY.Bus, sys)) variable_active = add_variable_container!(container, T(), PSY.Bus, "P", bus_numbers, time_steps) variable_reactive = diff --git a/src/network_models/pm_translator.jl b/src/network_models/pm_translator.jl index a699550774..8ab30cf44e 100644 --- a/src/network_models/pm_translator.jl +++ b/src/network_models/pm_translator.jl @@ -465,7 +465,7 @@ function pass_to_pm(sys::PSY.System, template::ProblemTemplate, time_periods::In template.branches, length(ac_lines), ) - buses = PSY.get_components(PSY.Bus, sys) + buses = PSY.get_available_components(PSY.Bus, sys) pm_buses, PMmap_buses = get_buses_to_pm(buses) PM_translation = Dict{String, Any}( "bus" => pm_buses, diff --git a/src/network_models/powermodels_interface.jl b/src/network_models/powermodels_interface.jl index 01fea7b452..be8ff75da4 100644 --- a/src/network_models/powermodels_interface.jl +++ b/src/network_models/powermodels_interface.jl @@ -291,7 +291,7 @@ function powermodels_network!( ) where {S <: PM.AbstractPowerModel} time_steps = get_time_steps(container) pm_data, PM_map = pass_to_pm(sys, template, time_steps[end]) - buses = PSY.get_components(PSY.Bus, sys) + buses = PSY.get_available_components(PSY.Bus, sys) for t in time_steps, bus in buses pm_data["nw"]["$(t)"]["bus"]["$(bus.number)"]["inj_p"] = @@ -319,7 +319,7 @@ function powermodels_network!( ) where {S <: PM.AbstractActivePowerModel} time_steps = get_time_steps(container) pm_data, PM_map = pass_to_pm(sys, template, time_steps[end]) - buses = PSY.get_components(PSY.Bus, sys) + buses = PSY.get_available_components(PSY.Bus, sys) for t in time_steps, bus in buses pm_data["nw"]["$(t)"]["bus"]["$(PSY.get_number(bus))"]["inj_p"] = From 939d13030348718d12d394a6c07ff0b530898cb7 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 11 May 2023 17:20:53 -0600 Subject: [PATCH 115/370] add request re-exports --- src/PowerSimulations.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 51f5c64e42..b1e31398f6 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -361,6 +361,9 @@ import JSON3 import PowerSystems import InfrastructureSystems import PowerNetworkMatrices +import PowerNetworkMatrices: PTDF, VirtualPTDF +export PTDF +export VirtualPTDF import InfrastructureSystems: @assert_op, list_recorder_events, get_name export get_name export get_model_base_power From 568b7bbf4cc61d8ead4dbc82493b6258608a22bf Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 11 May 2023 17:21:06 -0600 Subject: [PATCH 116/370] employ correct get available components --- src/core/network_model.jl | 2 +- src/devices_models/devices/common/add_constraint_dual.jl | 2 +- src/devices_models/devices/common/add_to_expression.jl | 4 ++-- src/network_models/network_slack_variables.jl | 4 ++-- src/network_models/pm_translator.jl | 3 +-- src/network_models/powermodels_interface.jl | 4 ++-- src/utils/powersystems_utils.jl | 6 +++++- 7 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/core/network_model.jl b/src/core/network_model.jl index c6217c938d..07b514fd76 100644 --- a/src/core/network_model.jl +++ b/src/core/network_model.jl @@ -113,7 +113,7 @@ function _assign_subnetworks_to_buses( ) where {T <: Union{CopperPlatePowerModel, StandardPTDFModel}} subnetworks = model.subnetworks temp_bus_map = Dict{Int, Int}() - for bus in PSY.get_available_components(PSY.Bus, sys) + for bus in get_available_components(PSY.Bus, sys) bus_no = PSY.get_number(bus) if haskey(temp_bus_map, bus_no) model.bus_area_map[bus] = temp_bus_map[bus_no] diff --git a/src/devices_models/devices/common/add_constraint_dual.jl b/src/devices_models/devices/common/add_constraint_dual.jl index 5c5f5a1e5c..5527c48315 100644 --- a/src/devices_models/devices/common/add_constraint_dual.jl +++ b/src/devices_models/devices/common/add_constraint_dual.jl @@ -19,7 +19,7 @@ function add_constraint_dual!( model::NetworkModel{T}, ) where {T <: PM.AbstractPowerModel} if !isempty(get_duals(model)) - devices = PSY.get_available_components(PSY.Bus, sys) + devices = get_available_components(PSY.Bus, sys) for constraint_type in get_duals(model) assign_dual_variable!(container, constraint_type, devices, model) end diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 9894d82bb4..ba24c91f15 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -913,7 +913,7 @@ function add_to_expression!( } variable = get_variable(container, U(), PSY.Bus, "P") expression = get_expression(container, T(), PSY.Bus) - bus_numbers = PSY.get_number.(PSY.get_available_components(PSY.Bus, sys)) + bus_numbers = PSY.get_number.(get_available_components(PSY.Bus, sys)) for t in get_time_steps(container), n in bus_numbers _add_to_jump_expression!( expression[n, t], @@ -937,7 +937,7 @@ function add_to_expression!( } variable = get_variable(container, U(), PSY.Bus, "Q") expression = get_expression(container, T(), PSY.Bus) - bus_numbers = PSY.get_number.(PSY.get_available_components(PSY.Bus, sys)) + bus_numbers = PSY.get_number.(get_available_components(PSY.Bus, sys)) for t in get_time_steps(container), n in bus_numbers _add_to_jump_expression!( expression[n, t], diff --git a/src/network_models/network_slack_variables.jl b/src/network_models/network_slack_variables.jl index d29d673d1a..a40a16a25d 100644 --- a/src/network_models/network_slack_variables.jl +++ b/src/network_models/network_slack_variables.jl @@ -37,7 +37,7 @@ function add_variables!( U <: PM.AbstractActivePowerModel, } time_steps = get_time_steps(container) - bus_numbers = PSY.get_number.(PSY.get_available_components(PSY.Bus, sys)) + bus_numbers = PSY.get_number.(get_available_components(PSY.Bus, sys)) variable = add_variable_container!(container, T(), PSY.Bus, bus_numbers, time_steps) for t in time_steps, n in bus_numbers @@ -60,7 +60,7 @@ function add_variables!( U <: PM.AbstractPowerModel, } time_steps = get_time_steps(container) - bus_numbers = PSY.get_number.(PSY.get_available_components(PSY.Bus, sys)) + bus_numbers = PSY.get_number.(get_available_components(PSY.Bus, sys)) variable_active = add_variable_container!(container, T(), PSY.Bus, "P", bus_numbers, time_steps) variable_reactive = diff --git a/src/network_models/pm_translator.jl b/src/network_models/pm_translator.jl index 8ab30cf44e..b311268033 100644 --- a/src/network_models/pm_translator.jl +++ b/src/network_models/pm_translator.jl @@ -1,7 +1,6 @@ const PM_MAP_TUPLE = NamedTuple{(:from_to, :to_from), Tuple{Tuple{Int, Int, Int}, Tuple{Int, Int, Int}}} - const PM_BUSTYPES = Dict{PSY.BusTypes, Int}( PSY.BusTypes.ISOLATED => 4, PSY.BusTypes.PQ => 1, @@ -465,7 +464,7 @@ function pass_to_pm(sys::PSY.System, template::ProblemTemplate, time_periods::In template.branches, length(ac_lines), ) - buses = PSY.get_available_components(PSY.Bus, sys) + buses = get_available_components(PSY.Bus, sys) pm_buses, PMmap_buses = get_buses_to_pm(buses) PM_translation = Dict{String, Any}( "bus" => pm_buses, diff --git a/src/network_models/powermodels_interface.jl b/src/network_models/powermodels_interface.jl index be8ff75da4..263844772e 100644 --- a/src/network_models/powermodels_interface.jl +++ b/src/network_models/powermodels_interface.jl @@ -291,7 +291,7 @@ function powermodels_network!( ) where {S <: PM.AbstractPowerModel} time_steps = get_time_steps(container) pm_data, PM_map = pass_to_pm(sys, template, time_steps[end]) - buses = PSY.get_available_components(PSY.Bus, sys) + buses = get_available_components(PSY.Bus, sys) for t in time_steps, bus in buses pm_data["nw"]["$(t)"]["bus"]["$(bus.number)"]["inj_p"] = @@ -319,7 +319,7 @@ function powermodels_network!( ) where {S <: PM.AbstractActivePowerModel} time_steps = get_time_steps(container) pm_data, PM_map = pass_to_pm(sys, template, time_steps[end]) - buses = PSY.get_available_components(PSY.Bus, sys) + buses = get_available_components(PSY.Bus, sys) for t in time_steps, bus in buses pm_data["nw"]["$(t)"]["bus"]["$(PSY.get_number(bus))"]["inj_p"] = diff --git a/src/utils/powersystems_utils.jl b/src/utils/powersystems_utils.jl index d7303f214f..2af80e6319 100644 --- a/src/utils/powersystems_utils.jl +++ b/src/utils/powersystems_utils.jl @@ -19,7 +19,11 @@ function get_available_components( sys::PSY.System, ::Nothing = nothing, ) - return PSY.get_components(x -> PSY.get_bustype(x) != PSY.BusTypes.ISOLATED, PSY.Bus, sys) + return PSY.get_components( + x -> PSY.get_bustype(x) != PSY.BusTypes.ISOLATED, + PSY.Bus, + sys, + ) end function get_available_components( From 1dda4640561a859234d07a92f2f4e50609239e59 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 11 May 2023 17:32:18 -0600 Subject: [PATCH 117/370] add test for isolated bus in the system --- test/test_model_decision.jl | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/test/test_model_decision.jl b/test/test_model_decision.jl index c2d4299938..12f3cb8074 100644 --- a/test/test_model_decision.jl +++ b/test/test_model_decision.jl @@ -680,3 +680,40 @@ end ) @test "Alta" ∉ axes(p_variable, 1) end + +@testset "Test for isolated buses" begin + c_sys5 = PSB.build_system(PSITestSystems, "c_sys5") + add_component!(c_sys5, + Bus( + 10, + "node_none", + "ISOLATED", + 0, + 1.0, + (min = 0.9, max = 1.05), + 230, + nothing, + nothing, + ), + ) + + template = get_thermal_standard_uc_template() + new_model = DeviceModel( + ThermalStandard, + ThermalBasicUnitCommitment; + ) + set_device_model!(template, new_model) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "test"), + ) + UC = DecisionModel( + template, + c_sys5; + optimizer = GLPK_optimizer, + detailed_optimizer_stats = true, + ) + output_dir = mktempdir(; cleanup = true) + @test build!(UC; output_dir = output_dir) == PSI.BuildStatus.BUILT + @test solve!(UC) == RunStatus.SUCCESSFUL +end From bebcf0d5630f0d1f5ffe471027481452e2a8b187 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 12 May 2023 12:31:28 -0600 Subject: [PATCH 118/370] Bump version to v0.20.2 --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 8858201909..b65bf62e24 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "PowerSimulations" uuid = "e690365d-45e2-57bb-ac84-44ba829e73c4" authors = ["Jose Daniel Lara", "Clayton Barrows", "Daniel Thom", "Dheepak Krishnamurthy", "Sourabh Dalvi"] -version = "0.20.1" +version = "0.20.2" [deps] CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" From 069ac1d633dc9e71c6e7c425239d84bf5ab889d1 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 9 May 2023 11:57:38 -0600 Subject: [PATCH 119/370] remove code --- docs/make.jl | 1 - docs/src/formulation_library/General.md | 8 +- docs/src/formulation_library/HydroGen.md | 494 ------ src/PowerSimulations.jl | 8 - src/core/formulations.jl | 33 - .../hydrogeneration_constructor.jl | 1482 ----------------- .../devices/hydro_generation.jl | 822 --------- ...st_device_hydro_generation_constructors.jl | 642 ------- test/test_services_constructor.jl | 23 - 9 files changed, 4 insertions(+), 3509 deletions(-) delete mode 100644 docs/src/formulation_library/HydroGen.md delete mode 100644 src/devices_models/device_constructors/hydrogeneration_constructor.jl delete mode 100644 src/devices_models/devices/hydro_generation.jl delete mode 100644 test/test_device_hydro_generation_constructors.jl diff --git a/docs/make.jl b/docs/make.jl index 0fc90a93a8..f2ec3aaedb 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -30,7 +30,6 @@ pages = OrderedDict( "Formulation Library" => Any[ "General" => "formulation_library/General.md", "Thermal Generation" => "formulation_library/ThermalGen.md", - "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", diff --git a/docs/src/formulation_library/General.md b/docs/src/formulation_library/General.md index 26d11eefa1..8b69c0803a 100644 --- a/docs/src/formulation_library/General.md +++ b/docs/src/formulation_library/General.md @@ -29,7 +29,7 @@ using PowerSystems using DataFrames using Latexify combo_tables = [] -for t in [RenewableGen, ThermalGen, HydroGen, Storage, ElectricLoad] +for t in [RenewableGen, ThermalGen, ElectricLoad] combos = PowerSimulations.get_default_time_series_names(t, FixedOutput) combo_table = DataFrame( "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), @@ -84,9 +84,9 @@ PowerSimulations can represent variable costs using a variety of different metho ### Piecewise Linear `VariableCost` -`variable_cost <: Vector{Tuple{Float64, Float64}}`: creates a piecewise linear cost term in the objective function +`variable_cost <: Vector{Tuple{Float64, Float64}}`: creates a piecewise linear cost term in the objective function -TODO: add formulation +TODO: add formulation ___ @@ -96,7 +96,7 @@ Adds an objective function cost term according to: ```math \begin{aligned} -& \text{min} \sum_{t} \quad [E^{surplus}_t * C^{penalty} - E^{shortage}_t * C^{value}] +& \text{min} \sum_{t} \quad [E^{surplus}_t * C^{penalty} - E^{shortage}_t * C^{value}] \end{aligned} ``` diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md deleted file mode 100644 index fa9358547d..0000000000 --- a/docs/src/formulation_library/HydroGen.md +++ /dev/null @@ -1,494 +0,0 @@ -# `PowerSystems.HydroGen` Formulations - -Valid `DeviceModel`s for subtypes of `HydroGen` include the following: - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.generate_device_formulation_combinations() -filter!(x -> x["device_type"] <: HydroGen, combos) -combo_table = DataFrame( - "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], - "Device Type" => ["[$(c["device_type"])](https://nrel-siip.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], - "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], - ) -mdtable(combo_table, latex = false) -``` - ---- - -## `HydroDispatchRunOfRiver` - -```@docs -HydroDispatchRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroDispatchRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} -\end{aligned} -``` - ---- - -## `HydroDispatchPumpedStorage` - -```@docs -HydroDispatchPumpedStorage -``` - -**Variables:** - -- [`ActivePowerInVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `-1 * PowerSystems.get_active_power(device)` -- [`ActivePowerOutVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`EnergyVariableUp`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device).up` -- [`EnergyVariableDown`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device).down` -- [`WaterSpillageVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`EnergyOutput`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`ReservationVariable`](@ref): - - only included if `DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage; attributes = Dict(reservation => true))` - - Bounds: {0, 1} - - Default initial value: 1 - -**Static Parameters:** - -- ``Pg^\text{out, max}`` = `map(x -> x.max - x.min, PowerSystems.get_active_power_limits(device))` -- ``Pg^\text{in, max}`` = `map(x -> x.max - x.min, PowerSystems.get_active_power_limits_pump(device))` -- ``Eg^\text{up, max}`` = `PowerSystems.get_storage_capacity(device).up` -- ``Eg^\text{down, max}`` = `PowerSystems.get_storage_capacity(device).down` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroPumpedStorage, HydroDispatchPumpedStorage) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg^{out}``. - -**Expressions:** - -Adds ``Pg`` term(s) to the active power balance expression(s) created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& E^{up}_{t+1} = E^{up}_t + (InflowTimeSeriesParameter_t - S_t - Pg^{out}_t + Pg^{in}_t) \cdot \Delta T \\ -& E^{down}_{t+1} = E^{down}_t + (S_t - OutflowTimeSeriesParameter_t + Pg^{out}_t - Pg^{in}_t) \cdot \Delta T \\ -& Pg^{in}_t - r * Pg^\text{in, max} \le Pg^\text{in, max} \\ -& Pg^{out}_t + r * Pg^\text{out, max} \le Pg^\text{out, max} \\ -& E^{up}_t \le E^{up, max} -& E^{down}_t \le E^{down, max} -\end{aligned} -``` - ---- - -## `HydroDispatchReservoirBudget` - -```@docs -HydroDispatchReservoirBudget -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - TODO - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroDispatchReservoirBudget) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg^\text{min} \le Pg_t \le Pg^\text{max} \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} \\ -& \sum_{t = 1}^N(Pg_t) \cdot \Delta T \le \sum_{t = 1}^N(EnergyBudgetTimeSeriesParameter_t) \cdot \Delta T -\end{aligned} -``` - ---- - -## `HydroDispatchReservoirStorage` - -```@docs -HydroDispatchReservoirStorage -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`EnergyVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device)` -- [`WaterSpillageVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`EnergyShortageVariable`](@ref): - - Bounds: [ , 0.0] - - Default initial value: 0.0 -- [`EnergySurplusVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` -- ``Eg^\text{max}`` = `PowerSystems.get_storage_capacity(device)` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroDispatchReservoirStorage) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. -TODO: add slack terms - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& E_{t+1} = E_t + (InflowTimeSeriesParameter_t - S_t - Pg_t) \cdot \Delta T \\ -& E_t - E^{surplus}_t + E^{shortage}_t = EnergyTargetTimeSeriesParameter_t \\ -& Pg^\text{min} \le Pg_t \le Pg^\text{max} \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} -\end{aligned} -``` - ---- - -## `HydroCommitmentReservoirBudget` - -```@docs -HydroCommitmentReservoirBudget -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - TODO - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroCommitmentReservoirBudget) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& \sum_{t = 1}^N P_t \cdot \Delta T \le E^\text{budget} \\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` - ---- - -## `HydroCommitmentReservoirStorage` - -```@docs -HydroCommitmentReservoirStorage -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`EnergyVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device)` -- [`WaterSpillageVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`EnergyShortageVariable`](@ref): - - Bounds: [ , 0.0] - - Default initial value: 0.0 -- [`EnergySurplusVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` -- ``Eg^\text{max}`` = `PowerSystems.get_storage_capacity(device)` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroCommitmentReservoirStorage) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``, -and objective function terms for [StorageManagementCost](@ref). - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& E_{t+1} = E_t + (InflowTimeSeriesParameter_t - S_t - Pg_t) \cdot \Delta T \\ -& E_t - E^{surplus}_t + E^{shortage}_t = EnergyTargetTimeSeriesParameter_t \\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` - ---- - -## `HydroCommitmentRunOfRiver` - -```@docs -HydroCommitmentRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroCommitmentRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg_t \le Pg^\text{max}\\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index b1e31398f6..7b0705a91e 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -51,14 +51,6 @@ export PowerLoadDispatch ######## Renewable Formulations ######## export RenewableFullDispatch export RenewableConstantPowerFactor -######## Hydro Formulations ######## -export HydroDispatchRunOfRiver -export HydroDispatchReservoirBudget -export HydroDispatchReservoirStorage -export HydroCommitmentRunOfRiver -export HydroCommitmentReservoirBudget -export HydroCommitmentReservoirStorage -export HydroDispatchPumpedStorage ######## Thermal Formulations ######## export ThermalStandardUnitCommitment diff --git a/src/core/formulations.jl b/src/core/formulations.jl index dedffc553a..948289a0e0 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -74,45 +74,12 @@ struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end ############################ Hydro Generation Formulations ################################# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end -abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end -abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end -abstract type AbstractHydroReservoirFormulation <: AbstractHydroDispatchFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end -""" -Formulation type to add injection variables constrained by total energy production budget defined with a time series for `HydroGen` -""" -struct HydroDispatchReservoirBudget <: AbstractHydroReservoirFormulation end - -""" -Formulation type to constrain hydropower production with a representation of the energy storage capacity and water inflow time series of a reservoir for `HydroGen` -""" -struct HydroDispatchReservoirStorage <: AbstractHydroReservoirFormulation end - -""" -Formulation type to constrain energy production from pumped storage with a representation of the energy storage capacity of upper and lower reservoirs and water inflow time series of upper reservoir and outflow time series of lower reservoir for `HydroPumpedStorage` -""" -struct HydroDispatchPumpedStorage <: AbstractHydroReservoirFormulation end - -""" -Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` -""" -struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end - -""" -Formulation type to add commitment and injection variables constrained by total energy production budget defined with a time series for `HydroGen` -""" -struct HydroCommitmentReservoirBudget <: AbstractHydroUnitCommitment end - -""" -Formulation type to constrain hydropower production with unit commitment variables and a representation of the energy storage capacity and water inflow time series of a reservoir for `HydroGen` -""" -struct HydroCommitmentReservoirStorage <: AbstractHydroUnitCommitment end - ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end struct ReserveLimitedRegulation <: AbstractRegulationFormulation end diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl deleted file mode 100644 index a2483f8e70..0000000000 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ /dev/null @@ -1,1482 +0,0 @@ -""" -Construct model for HydroGen with FixedOutput Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -function construct_device!( - ::OptimizationContainer, - ::PSY.System, - ::ModelConstructStage, - ::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - # FixedOutput doesn't add any constraints to the model. This function covers - # AbstractPowerModel and AbtractActivePowerModel - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -""" -Construct model for HydroGen with RunOfRiver Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with RunOfRiver Dispatch Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirBudget Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirBudget()) - add_variables!( - container, - ReactivePowerVariable, - devices, - HydroDispatchReservoirBudget(), - ) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirBudget()) - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirBudget Dispatch Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirBudget()) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirBudget()) - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with ReservoirStorage Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirStorage()) - add_variables!( - container, - ReactivePowerVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!(container, EnergyVariable, devices, HydroDispatchReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirStorage()) - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroDispatchReservoirStorage(), - InitialEnergyLevel(), - ) - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirStorage Dispatch Formulation -with only Active Power -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirStorage()) - add_variables!(container, EnergyVariable, devices, HydroDispatchReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirStorage()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroDispatchReservoirStorage(), - InitialEnergyLevel(), - ) - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirBudget Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentReservoirBudget, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentReservoirBudget, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with ReservoirBudget Commitment Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentReservoirBudget, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentReservoirBudget, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirStorage Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!( - container, - ActivePowerVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - ReactivePowerVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!(container, OnVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!(container, EnergyVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!(container, EnergyOutput, devices, HydroCommitmentReservoirStorage()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroCommitmentReservoirStorage(), - InitialEnergyLevel(), - ) - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with ReservoirStorage Dispatch Formulation -with only Active Power -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!( - container, - ActivePowerVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!(container, OnVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!(container, EnergyVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_variables!(container, EnergyOutput, devices, HydroCommitmentReservoirStorage()) - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroCommitmentReservoirStorage(), - InitialEnergyLevel(), - ) - - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroPumpedStorage with PumpedStorage Dispatch Formulation -with only Active Power -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchPumpedStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroPumpedStorage, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerInVariable, devices, HydroDispatchPumpedStorage()) - add_variables!(container, ActivePowerOutVariable, devices, HydroDispatchPumpedStorage()) - add_variables!(container, EnergyVariableUp, devices, HydroDispatchPumpedStorage()) - add_variables!(container, EnergyVariableDown, devices, HydroDispatchPumpedStorage()) - add_variables!(container, WaterSpillageVariable, devices, HydroDispatchPumpedStorage()) - add_variables!(container, EnergyOutput, devices, HydroDispatchPumpedStorage()) - if get_attribute(model, "reservation") - add_variables!( - container, - ReservationVariable, - devices, - HydroDispatchPumpedStorage(), - ) - end - - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - add_parameters!(container, OutflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerInVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ReserveRangeExpressionLB, devices, model) - add_expressions!(container, ReserveRangeExpressionUB, devices, model) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchPumpedStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroPumpedStorage, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - OutputActivePowerVariableLimitsConstraint, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - InputActivePowerVariableLimitsConstraint, - ActivePowerInVariable, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroDispatchPumpedStorage(), - InitialEnergyLevelUp(), - ) - add_initial_condition!( - container, - devices, - HydroDispatchPumpedStorage(), - InitialEnergyLevelDown(), - ) - - # Energy Balanace limits - add_constraints!(container, EnergyCapacityUpConstraint, devices, model, network_model) - add_constraints!(container, EnergyCapacityDownConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl deleted file mode 100644 index 65792bb3bf..0000000000 --- a/src/devices_models/devices/hydro_generation.jl +++ /dev/null @@ -1,822 +0,0 @@ -#! format: off -requires_initialization(::AbstractHydroFormulation) = false -requires_initialization(::AbstractHydroUnitCommitment) = true - -get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroPumpedStorage}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ReserveRangeExpressionUB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroPumpedStorage}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ReserveRangeExpressionLB - -########################### ActivePowerVariable, HydroGen ################################# -get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 -get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max - -############## ActivePowerVariable, HydroDispatchRunOfRiver #################### -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 - -############## ReactivePowerVariable, HydroGen #################### -get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min -get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max - -############## EnergyVariable, HydroGen #################### -get_variable_binary(::EnergyVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(pv::EnergyVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d) -get_variable_lower_bound(::EnergyVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) - -########################### EnergyVariableUp, HydroGen ################################# -get_variable_binary(::EnergyVariableUp, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(pv::EnergyVariableUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).up -get_variable_lower_bound(::EnergyVariableUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyVariableUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d).up - -########################### EnergyVariableDown, HydroGen ################################# -get_variable_binary(::EnergyVariableDown, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::EnergyVariableDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).down -get_variable_lower_bound(::EnergyVariableDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyVariableDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d).down - -########################### ActivePowerInVariable, HydroGen ################################# -get_variable_binary(::ActivePowerInVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::ActivePowerInVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::ActivePowerInVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = nothing -get_variable_multiplier(::ActivePowerInVariable, d::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = -1.0 - -########################### ActivePowerOutVariable, HydroGen ################################# -get_variable_binary(::ActivePowerOutVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::ActivePowerOutVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::ActivePowerOutVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = nothing -get_variable_multiplier(::ActivePowerOutVariable, d::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 - -############## OnVariable, HydroGen #################### -get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true -get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 - -############## WaterSpillageVariable, HydroGen #################### -get_variable_binary(::WaterSpillageVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::WaterSpillageVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 - -############## ReservationVariable, HydroGen #################### -get_variable_binary(::ReservationVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true -get_variable_binary(::ReservationVariable, ::Type{<:PSY.HydroPumpedStorage}, ::AbstractHydroFormulation) = true - -############## EnergyShortageVariable, HydroGen #################### -get_variable_binary(::EnergyShortageVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::EnergyShortageVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyShortageVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) -get_variable_upper_bound(::EnergyShortageVariable, d::PSY.HydroPumpedStorage, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d).up -############## EnergySurplusVariable, HydroGen #################### -get_variable_binary(::EnergySurplusVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_upper_bound(::EnergySurplusVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_lower_bound(::EnergySurplusVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = - PSY.get_storage_capacity(d) -get_variable_lower_bound(::EnergySurplusVariable, d::PSY.HydroPumpedStorage, ::AbstractHydroFormulation) = - PSY.get_storage_capacity(d).up -########################### Parameter related set functions ################################ -get_multiplier_value(::EnergyBudgetTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::EnergyBudgetTimeSeriesParameter, d::PSY.HydroEnergyReservoir, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) -get_multiplier_value(::EnergyTargetTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) -get_multiplier_value(::InflowTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_inflow(d) * PSY.get_conversion_factor(d) -get_multiplier_value(::OutflowTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_outflow(d) * PSY.get_conversion_factor(d) -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) - -get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min - -#################### Initial Conditions for models ############### -initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) -initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() -initial_condition_default(::InitialEnergyLevel, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d) -initial_condition_variable(::InitialEnergyLevel, d::PSY.HydroGen, ::AbstractHydroFormulation) = EnergyVariable() -initial_condition_default(::InitialEnergyLevelUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).up -initial_condition_variable(::InitialEnergyLevelUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = EnergyVariableUp() -initial_condition_default(::InitialEnergyLevelDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).down -initial_condition_variable(::InitialEnergyLevelDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = EnergyVariableDown() -initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 -initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) -initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() - -########################Objective Function################################################## -proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 -proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_surplus_cost(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_shortage_cost(cost) - -objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::EnergySurplusVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_NEGATIVE -objective_function_multiplier(::EnergyShortageVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE - -sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE -sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE - -variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 -variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) -variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) - -#! format: on - -function get_initial_conditions_device_model( - ::OperationModel, - model::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroEnergyReservoir} - return model -end - -function get_initial_conditions_device_model( - ::OperationModel, - ::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroDispatch} - return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) -end - -function get_initial_conditions_device_model( - ::OperationModel, - ::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroPumpedStorage} - return DeviceModel(PSY.HydroPumpedStorage, HydroDispatchPumpedStorage) -end - -function get_default_time_series_names( - ::Type{<:PSY.HydroGen}, - ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - ActivePowerTimeSeriesParameter => "max_active_power", - ReactivePowerTimeSeriesParameter => "max_active_power", - ) -end - -function get_default_time_series_names( - ::Type{PSY.HydroEnergyReservoir}, - ::Type{<:Union{HydroCommitmentReservoirBudget, HydroDispatchReservoirBudget}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - EnergyBudgetTimeSeriesParameter => "hydro_budget", - ) -end - -function get_default_time_series_names( - ::Type{PSY.HydroEnergyReservoir}, - ::Type{<:Union{HydroDispatchReservoirStorage, HydroCommitmentReservoirStorage}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - EnergyTargetTimeSeriesParameter => "storage_target", - InflowTimeSeriesParameter => "inflow", - ) -end - -function get_default_time_series_names( - ::Type{PSY.HydroPumpedStorage}, - ::Type{<:HydroDispatchPumpedStorage}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - InflowTimeSeriesParameter => "inflow", - OutflowTimeSeriesParameter => "outflow", - ) -end - -function get_default_attributes( - ::Type{T}, - ::Type{D}, -) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} - return Dict{String, Any}("reservation" => false) -end - -function get_default_attributes( - ::Type{PSY.HydroPumpedStorage}, - ::Type{HydroDispatchPumpedStorage}, -) - return Dict{String, Any}("reservation" => true) -end - -""" -Time series constraints -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:RangeConstraintLBExpressions}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -""" -Add semicontinuous range constraints for Hydro Unit Commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -""" -Min and max reactive Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ReactivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_reactive_power_limits(x) -end - -""" -Min and max active Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_active_power_limits(x) -end - -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchRunOfRiver}, -) - return (min = 0.0, max = PSY.get_max_active_power(x)) -end - -""" -Add power variable limits constraints for hydro unit commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -""" -Add power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroGen, - W <: AbstractHydroDispatchFormulation, - X <: PM.AbstractPowerModel, -} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -""" -Add input power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{InputActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroReservoirFormulation, - X <: PM.AbstractPowerModel, -} - if get_attribute(model, "reservation") - add_reserve_range_constraints!(container, T, U, devices, model, X) - else - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - end - return -end - -""" -Add output power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroReservoirFormulation, - X <: PM.AbstractPowerModel, -} - if get_attribute(model, "reservation") - add_reserve_range_constraints!(container, T, U, devices, model, X) - else - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - end - return -end - -""" -Min and max output active power variable limits for hydro dispatch pumped storage -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:OutputActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchPumpedStorage}, -) - return PSY.get_active_power_limits(x) -end - -""" -Min and max input active power variable limits for hydro dispatch pumped storage -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:InputActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchPumpedStorage}, -) - return PSY.get_active_power_limits_pump(x) -end - -######################## Energy balance constraints ############################ - -""" -This function defines the constraints for the water level (or state of charge) -for the Hydro Reservoir. -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyBalanceConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroEnergyReservoir, - W <: AbstractHydroFormulation, - X <: PM.AbstractPowerModel, -} - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - names = [PSY.get_name(x) for x in devices] - initial_conditions = get_initial_condition(container, InitialEnergyLevel(), V) - energy_var = get_variable(container, EnergyVariable(), V) - power_var = get_variable(container, ActivePowerVariable(), V) - spillage_var = get_variable(container, WaterSpillageVariable(), V) - - constraint = add_constraints_container!( - container, - EnergyBalanceConstraint(), - V, - names, - time_steps, - ) - param_container = get_parameter(container, InflowTimeSeriesParameter(), V) - multiplier = get_parameter_multiplier_array(container, InflowTimeSeriesParameter(), V) - - for ic in initial_conditions - device = get_component(ic) - name = PSY.get_name(device) - param = get_parameter_column_values(param_container, name) - constraint[name, 1] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, 1] == - get_value(ic) - power_var[name, 1] * fraction_of_hour - - spillage_var[name, 1] * fraction_of_hour + param[1] * multiplier[name, 1] - ) - - for t in time_steps[2:end] - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, t] == - energy_var[name, t - 1] + param[t] * multiplier[name, t] - - power_var[name, t] * fraction_of_hour - - spillage_var[name, t] * fraction_of_hour - ) - end - end - return -end - -""" -This function defines the constraints for the water level (or state of charge) -for the HydroPumpedStorage. -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyCapacityUpConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroFormulation, - X <: PM.AbstractPowerModel, -} - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - names = [PSY.get_name(x) for x in devices] - initial_conditions = get_initial_condition(container, InitialEnergyLevelUp(), V) - - energy_var = get_variable(container, EnergyVariableUp(), V) - powerin_var = get_variable(container, ActivePowerInVariable(), V) - powerout_var = get_variable(container, ActivePowerOutVariable(), V) - spillage_var = get_variable(container, WaterSpillageVariable(), V) - - constraint = add_constraints_container!( - container, - EnergyCapacityUpConstraint(), - V, - names, - time_steps, - ) - param_container = get_parameter(container, InflowTimeSeriesParameter(), V) - multiplier = get_multiplier_array(param_container) - - for ic in initial_conditions - device = get_component(ic) - efficiency = PSY.get_pump_efficiency(device) - name = PSY.get_name(device) - constraint[name, 1] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, 1] == - get_value(ic) + - ( - powerin_var[name, 1] - - (spillage_var[name, 1] + powerout_var[name, 1]) / efficiency - ) * fraction_of_hour + - get_parameter_column_refs(param_container, name)[1] * multiplier[name, 1] - ) - - for t in time_steps[2:end] - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, t] == - energy_var[name, t - 1] + - get_parameter_column_refs(param_container, name)[t] * multiplier[name, t] + - ( - powerin_var[name, 1] - - (powerout_var[name, t] + spillage_var[name, t]) / efficiency - ) * fraction_of_hour - ) - end - end - return -end - -""" -Add energy capacity down constraints for hydro pumped storage -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyCapacityDownConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroFormulation, - X <: PM.AbstractPowerModel, -} - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - names = [PSY.get_name(x) for x in devices] - initial_conditions = get_initial_condition(container, InitialEnergyLevelDown(), V) - - energy_var = get_variable(container, EnergyVariableDown(), V) - powerin_var = get_variable(container, ActivePowerInVariable(), V) - powerout_var = get_variable(container, ActivePowerOutVariable(), V) - spillage_var = get_variable(container, WaterSpillageVariable(), V) - - constraint = add_constraints_container!( - container, - EnergyCapacityDownConstraint(), - V, - names, - time_steps, - ) - - param_container = get_parameter(container, OutflowTimeSeriesParameter(), V) - multiplier = get_multiplier_array(param_container) - - for ic in initial_conditions - device = get_component(ic) - efficiency = PSY.get_pump_efficiency(device) - name = PSY.get_name(device) - param = get_parameter_column_refs(param_container, name) - constraint[name, 1] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, 1] == - get_value(ic) - - ( - spillage_var[name, 1] + powerout_var[name, 1] - - powerin_var[name, 1] / efficiency - ) * fraction_of_hour - param[1] * multiplier[name, 1] - ) - - for t in time_steps[2:end] - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, t] == - energy_var[name, t - 1] - param[t] * multiplier[name, t] + - ( - powerout_var[name, t] - powerin_var[name, t] / efficiency + - spillage_var[name, t] - ) * fraction_of_hour - ) - end - end - return -end - -""" -Add energy target constraints for hydro gen -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyTargetConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroFormulation, X <: PM.AbstractPowerModel} - time_steps = get_time_steps(container) - set_name = [PSY.get_name(d) for d in devices] - constraint = add_constraints_container!( - container, - EnergyTargetConstraint(), - V, - set_name, - time_steps, - ) - - e_var = get_variable(container, EnergyVariable(), V) - shortage_var = get_variable(container, EnergyShortageVariable(), V) - surplus_var = get_variable(container, EnergySurplusVariable(), V) - param_container = get_parameter(container, EnergyTargetTimeSeriesParameter(), V) - multiplier = - get_parameter_multiplier_array(container, EnergyTargetTimeSeriesParameter(), V) - - for d in devices - name = PSY.get_name(d) - cost_data = PSY.get_operation_cost(d) - if isa(cost_data, PSY.StorageManagementCost) - shortage_cost = PSY.get_energy_shortage_cost(cost_data) - else - @debug "Data for device $name doesn't contain shortage costs" - shortage_cost = 0.0 - end - - if shortage_cost == 0.0 - @warn( - "Device $name has energy shortage cost set to 0.0, as a result the model will turnoff the EnergyShortageVariable to avoid infeasible/unbounded problem." - ) - JuMP.delete_upper_bound.(shortage_var[name, :]) - JuMP.set_upper_bound.(shortage_var[name, :], 0.0) - end - param = get_parameter_column_values(param_container, name) - for t in time_steps - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - e_var[name, t] + shortage_var[name, t] + surplus_var[name, t] == - multiplier[name, t] * param[t] - ) - end - end - return -end - -##################################### Water/Energy Budget Constraint ############################ -""" -This function define the budget constraint for the -active power budget formulation. - -`` sum(P[t]) <= Budget `` -""" - -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyBudgetConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroFormulation, X <: PM.AbstractPowerModel} - time_steps = get_time_steps(container) - set_name = [PSY.get_name(d) for d in devices] - constraint = - add_constraints_container!(container, EnergyBudgetConstraint(), V, set_name) - - variable_out = get_variable(container, ActivePowerVariable(), V) - param_container = get_parameter(container, EnergyBudgetTimeSeriesParameter(), V) - multiplier = get_multiplier_array(param_container) - - for d in devices - name = PSY.get_name(d) - param = get_parameter_column_values(param_container, name) - constraint[name] = JuMP.@constraint( - container.JuMPmodel, - sum([variable_out[name, t] for t in time_steps]) <= - sum([multiplier[name, t] * param[t] for t in time_steps]) - ) - end - return -end - -##################################### Auxillary Variables ############################ -function _calculate_aux_variable_value!( - container::OptimizationContainer, - ::AuxVarKey{EnergyOutput, T}, - system::PSY.System, - p_variable_results::JuMPVariableArray, -) where {T <: PSY.HydroGen} - devices = axes(p_variable_results, 1) - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - aux_variable_container = get_aux_variable(container, EnergyOutput(), T) - for name in devices, t in time_steps - aux_variable_container[name, t] = - jump_value(p_variable_results[name, t]) * fraction_of_hour - end - - return -end - -function calculate_aux_variable_value!( - container::OptimizationContainer, - aux_key::AuxVarKey{EnergyOutput, T}, - system::PSY.System, -) where {T <: PSY.HydroGen} - p_variable_results = get_variable(container, ActivePowerVariable(), T) - _calculate_aux_variable_value!( - container, - aux_key, - system, - p_variable_results, - ) - return -end - -function calculate_aux_variable_value!( - container::OptimizationContainer, - aux_key::AuxVarKey{EnergyOutput, T}, - system::PSY.System, -) where {T <: PSY.HydroPumpedStorage} - p_variable_results = get_variable(container, ActivePowerOutVariable(), T) - _calculate_aux_variable_value!( - container, - aux_key, - system, - p_variable_results, - ) - return -end - -##################################### Hydro generation cost ############################ -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, OnVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{PSY.HydroPumpedStorage}, - ::DeviceModel{PSY.HydroPumpedStorage, T}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: HydroDispatchPumpedStorage} - add_variable_cost!(container, ActivePowerOutVariable(), devices, T()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where { - T <: PSY.HydroPumpedStorage, - U <: Union{HydroDispatchReservoirStorage, HydroDispatchReservoirBudget}, -} - add_variable_cost!(container, ActivePowerOutVariable(), devices, U()) - add_proportional_cost!(container, EnergySurplusVariable(), devices, U()) - add_proportional_cost!(container, EnergyShortageVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroEnergyReservoir, U <: HydroDispatchReservoirStorage} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, EnergySurplusVariable(), devices, U()) - add_proportional_cost!(container, EnergyShortageVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroEnergyReservoir, U <: HydroCommitmentReservoirStorage} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, EnergySurplusVariable(), devices, U()) - add_proportional_cost!(container, EnergyShortageVariable(), devices, U()) - return -end diff --git a/test/test_device_hydro_generation_constructors.jl b/test/test_device_hydro_generation_constructors.jl deleted file mode 100644 index ef37a71eab..0000000000 --- a/test/test_device_hydro_generation_constructors.jl +++ /dev/null @@ -1,642 +0,0 @@ -################################### -###### FIXED OUTPUT TESTS ######### -################################### - -@testset "Hydro DCPLossLess FixedOutput" begin - device_model = DeviceModel(HydroDispatch, FixedOutput) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with FixedOutput formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, FixedOutput) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -### RUN OF RIVER DISPATCH TESTS ### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -#### RUN OF RIVER COMMIT TESTS #### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -#### RESERVOIR BUDGET DISPATCH TESTS #### -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 25, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 49, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -#### PUMPED STORAGE DISPATCH TESTS #### -######################################### - -@testset "Hydro DCPLossLess HydroPumpedStorage with HydroDispatchPumpedStorage Formulations" begin - device_model = DeviceModel( - HydroPumpedStorage, - HydroDispatchPumpedStorage; - attributes = Dict{String, Any}("reservation" => false), - ) - c_sys5_phes_ed = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_phes_ed) - mock_construct_device!(model, device_model) - moi_tests(model, 60, 0, 24, 24, 24, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroPumpedStorage with HydroDispatchPumpedStorage with Reservation Formulations" begin - device_model = DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage) - c_sys5_phes_ed = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_phes_ed) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 24, 24, 24, true) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -### RESERVOIR BUDGET COMMITMENT TESTS ### -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 25, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 49, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -### RESERVOIR STORAGE DISPATCH TESTS #### -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 120, 0, 24, 24, 48, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPLossLess HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 144, 0, 48, 48, 48, false) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -### RESERVOIR STORAGE COMMITMENT TESTS ## -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 144, 0, 24, 24, 48, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPLossLess HydroEnergyReservoir with HydroCommitmentReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 168, 0, 48, 48, 48, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Solving ED Hydro System using Dispatch Run of River" begin - sys = PSB.build_system(PSITestSystems, "c_sys5_hy") - networks = [ACPPowerModel, DCPPowerModel] - - test_results = Dict{Any, Float64}(ACPPowerModel => 177526.0, DCPPowerModel => 175521.0) - - for net in networks - @testset "HydroRoR ED model $(net)" begin - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroDispatch, HydroDispatchRunOfRiver) - ED = DecisionModel( - EconomicDispatchProblem, - template, - sys; - optimizer = ipopt_optimizer, - ) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == - PSI.BuildStatus.BUILT - psi_checksolve_test( - ED, - [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], - test_results[net], - 1000, - ) - end - end -end - -@testset "Solving ED Hydro System using Commitment Run of River" begin - sys = PSB.build_system(PSITestSystems, "c_sys5_hy") - net = DCPPowerModel - - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroDispatch, HydroCommitmentRunOfRiver) - - @testset "HydroRoR ED model $(net)" begin - ED = DecisionModel(UnitCommitmentProblem, template, sys; optimizer = GLPK_optimizer) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - psi_checksolve_test(ED, [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], 175521.0, 1000) - end -end - -@testset "Solving ED Hydro System using Dispatch with Reservoir" begin - systems = [ - PSB.build_system(PSITestSystems, "c_sys5_hyd"), - PSB.build_system(PSITestSystems, "c_sys5_hyd_ems"), - ] - networks = [ACPPowerModel, DCPPowerModel] - models = [HydroDispatchReservoirBudget, HydroDispatchReservoirStorage] - test_results = Dict{Any, Float64}( - (ACPPowerModel, HydroDispatchReservoirBudget) => 33423.0, - (DCPPowerModel, HydroDispatchReservoirBudget) => 33042.0, - (ACPPowerModel, HydroDispatchReservoirStorage) => 232497.0, - (DCPPowerModel, HydroDispatchReservoirStorage) => 230153.0, - ) - - for net in networks, (mod, sys) in zip(models, systems) - @testset "$(mod) ED model on $(net)" begin - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroEnergyReservoir, mod) - - ED = DecisionModel( - EconomicDispatchProblem, - template, - sys; - optimizer = ipopt_optimizer, - ) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == - PSI.BuildStatus.BUILT - psi_checksolve_test( - ED, - [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], - test_results[(net, mod)], - 10000, - ) - end - end -end - -@testset "Solving ED Hydro System using Commitment with Reservoir" begin - systems = [ - PSB.build_system(PSITestSystems, "c_sys5_hyd"), - PSB.build_system(PSITestSystems, "c_sys5_hyd_ems"), - ] - net = DCPPowerModel - models = [HydroCommitmentReservoirBudget, HydroCommitmentReservoirStorage] - test_results = Dict{Any, Float64}( - HydroCommitmentReservoirBudget => 33042.0, - HydroCommitmentReservoirStorage => 230153.0, - ) - - for (mod, sys) in zip(models, systems) - @testset "$(mod) ED model on $(net) and use_parameters = true" begin - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroEnergyReservoir, mod) - - ED = DecisionModel( - UnitCommitmentProblem, - template, - sys; - optimizer = GLPK_optimizer, - ) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == - PSI.BuildStatus.BUILT - psi_checksolve_test( - ED, - [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], - test_results[mod], - 10000, - ) - end - end -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1b-2b)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_b_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], 5621.0, 10.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1c-2c)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_c_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], 21.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1d-2d)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_d_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], -5429.0, 10.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1e-2e)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_e_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], 21.0, 10.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1f-2f)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_f_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], -17179.0) -end - -### Feedforward Test ### - -@testset "Test SemiContinuousFeedforward to HydroDispatch with HydroCommitmentRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - ff_sc = SemiContinuousFeedforward(; - component_type = HydroDispatch, - source = OnVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_sc) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 96, 0, 72, 48, 0, true) -end - -@testset "Test UpperBoundFeedforward to HydroDispatch with HydroCommitmentRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - ff_ub = UpperBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 96, 0, 72, 24, 0, true) -end - -@testset "Test LowerBoundFeedforward to HydroDispatch with HydroCommitmentRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - ff_ub = LowerBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 96, 0, 48, 48, 0, true) -end - -@testset "Test UpperBoundFeedforward to HydroDispatch with HydroDispatchRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - - ff_ub = UpperBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 72, 0, 72, 24, 0, false) -end - -@testset "Test LowerBoundFeedforward to HydroDispatch with HydroDispatchRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - - ff_ub = LowerBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 72, 0, 48, 48, 0, false) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir with HydroDispatchReservoirBudget model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirBudget) - ff_il = EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 72, 0, 27, 24, 0, false) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir with HydroDispatchReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - ff_il = EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 193, 0, 26, 24, 48, false) -end - -@testset "Test LowerBoundFeedforward to HydroEnergyReservoir with HydroDispatchReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - ff_il = LowerBoundFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 193, 0, 24, 48, 48, false) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir with HydroCommitmentReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - ff_il = EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ) - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 217, 0, 26, 24, 48, true) -end - -@testset "Test SemiContinuousFeedforward to HydroEnergyReservoir with HydroCommitmentReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - ff_sc = SemiContinuousFeedforward(; - component_type = HydroEnergyReservoir, - source = OnVariable, - affected_values = [ActivePowerVariable], - ) - PSI.attach_feedforward!(device_model, ff_sc) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 217, 0, 48, 48, 48, true) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir models" begin - device_model = DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage) - - ff_il = EnergyLimitFeedforward(; - component_type = HydroPumpedStorage, - source = ActivePowerOutVariable, - affected_values = [ActivePowerOutVariable], - number_of_periods = 12, - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 110, 0, 25, 24, 24, true) -end - -@testset "Test EnergyTargetFeedforward to HydroEnergyReservoir models" begin - device_model = DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage) - - ff_up = EnergyTargetFeedforward(; - component_type = HydroPumpedStorage, - source = EnergyVariableUp, - affected_values = [EnergyVariableUp], - target_period = 12, - penalty_cost = 1e4, - ) - - PSI.attach_feedforward!(device_model, ff_up) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 122, 0, 24, 25, 24, true) -end diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index 9c4100a19c..c264dd41ac 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -132,29 +132,6 @@ end moi_tests(model, 360, 0, 72, 120, 72, false) end -@testset "Test Reserves from Hydro" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, PowerLoad, StaticPowerLoad) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchRunOfRiver) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve5"), - ) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveDown}, RangeReserve, "Reserve6"), - ) - set_service_model!( - template, - ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), - ) - - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; add_reserves = true) - model = DecisionModel(template, c_sys5_hyd) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 240, 0, 48, 96, 72, false) -end - @testset "Test Reserves from with slack variables" begin template = get_thermal_dispatch_template_network( NetworkModel(CopperPlatePowerModel; use_slacks = true), From ddee6e17c9b0ba0b6e3c6d813f532013e440b36e Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 25 Apr 2023 13:59:51 -0600 Subject: [PATCH 120/370] move more code --- src/PowerSimulations.jl | 5 ++- src/core/formulations.jl | 2 +- test/test_simulation_build.jl | 84 ----------------------------------- 3 files changed, 4 insertions(+), 87 deletions(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 7b0705a91e..f2c45c3dd4 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -67,6 +67,9 @@ export ThermalCompactDispatch export DeviceLimitedRegulation export ReserveLimitedRegulation +###### Hydro ####### +export HydroDispatchRunOfRiver + # feedforward models export UpperBoundFeedforward export LowerBoundFeedforward @@ -525,7 +528,6 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") -include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") # Services Models @@ -547,7 +549,6 @@ include("initial_conditions/initialization.jl") # Device constructors include("devices_models/device_constructors/constructor_validations.jl") include("devices_models/device_constructors/thermalgeneration_constructor.jl") -include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 948289a0e0..4916aef959 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -78,7 +78,7 @@ abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ -struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end +struct HydroDispatchRunOfRiver <: AbstractHydroFormulation end ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end diff --git a/test/test_simulation_build.jl b/test/test_simulation_build.jl index 5acd725af5..b2fbe6589d 100644 --- a/test/test_simulation_build.jl +++ b/test/test_simulation_build.jl @@ -132,90 +132,6 @@ end @test_throws IS.ConflictingInputsError PSI._check_folder(sim) end -@testset "Multi-Stage Hydro Simulation Build" begin - sys_md = PSB.build_system(PSISystems, "5_bus_hydro_wk_sys") - - sys_uc = PSB.build_system(PSISystems, "5_bus_hydro_uc_sys") - transform_single_time_series!(sys_uc, 48, Hour(24)) - - sys_ed = PSB.build_system(PSISystems, "5_bus_hydro_ed_sys") - - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, ThermalStandard, ThermalBasicUnitCommitment) - set_device_model!(template, PowerLoad, StaticPowerLoad) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirBudget) - - template_uc = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template_uc, ThermalStandard, ThermalBasicUnitCommitment) - set_device_model!(template_uc, PowerLoad, StaticPowerLoad) - set_device_model!(template_uc, HydroEnergyReservoir, HydroDispatchRunOfRiver) - - template_ed = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template_ed, ThermalStandard, ThermalBasicUnitCommitment) - set_device_model!(template_ed, PowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchRunOfRiver) - - models = SimulationModels([ - DecisionModel( - template, - sys_md; - name = "MD", - initialize_model = false, - system_to_file = false, - optimizer = HiGHS_optimizer, - ), - DecisionModel( - template_uc, - sys_uc; - name = "UC", - initialize_model = false, - system_to_file = false, - optimizer = HiGHS_optimizer, - ), - DecisionModel( - template_ed, - sys_ed; - name = "ED", - initialize_model = false, - system_to_file = false, - optimizer = HiGHS_optimizer, - ), - ]) - - feedforwards = Dict( - "UC" => [ - EnergyLimitFeedforward(; - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - component_type = HydroEnergyReservoir, - number_of_periods = 24, - ), - ], - "ED" => [ - EnergyLimitFeedforward(; - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - component_type = HydroEnergyReservoir, - number_of_periods = 12, - ), - ], - ) - - test_sequence = SimulationSequence(; - models = models, - ini_cond_chronology = InterProblemChronology(), - feedforwards = feedforwards, - ) - - sim = Simulation(; - name = "test_md", - steps = 2, - models = models, - sequence = test_sequence, - simulation_folder = mktempdir(; cleanup = true), - ) - @test build!(sim; serialize = false) == PSI.BuildStatus.BUILT -end @testset "Test SemiContinuous Feedforward with Active and Reactive Power variables" begin template_uc = get_template_basic_uc_simulation() From 82a9ef470d7b8308ef9e60ee6a684660ae9ddb86 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:35 -0700 Subject: [PATCH 121/370] bring back hydro constructors --- src/PowerSimulations.jl | 3 + src/core/formulations.jl | 9 +- .../hydrogeneration_constructor.jl | 468 ++++++++++++++++++ .../devices/hydro_generation.jl | 297 +++++++++++ 4 files changed, 776 insertions(+), 1 deletion(-) create mode 100644 src/devices_models/device_constructors/hydrogeneration_constructor.jl create mode 100644 src/devices_models/devices/hydro_generation.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index f2c45c3dd4..41a1f0c63b 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -69,6 +69,7 @@ export ReserveLimitedRegulation ###### Hydro ####### export HydroDispatchRunOfRiver +export HydroCommitmentRunOfRiver # feedforward models export UpperBoundFeedforward @@ -528,6 +529,7 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") +include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") # Services Models @@ -549,6 +551,7 @@ include("initial_conditions/initialization.jl") # Device constructors include("devices_models/device_constructors/constructor_validations.jl") include("devices_models/device_constructors/thermalgeneration_constructor.jl") +include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 4916aef959..7522280c51 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -74,11 +74,18 @@ struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end ############################ Hydro Generation Formulations ################################# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end +abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end +abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ -struct HydroDispatchRunOfRiver <: AbstractHydroFormulation end +struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end + +""" +Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` +""" +struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl new file mode 100644 index 0000000000..75673eba77 --- /dev/null +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -0,0 +1,468 @@ +""" +Construct model for HydroGen with FixedOutput Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) + + # Expression + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + return +end + +function construct_device!( + ::OptimizationContainer, + ::PSY.System, + ::ModelConstructStage, + ::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} + # FixedOutput doesn't add any constraints to the model. This function covers + # AbstractPowerModel and AbstractActivePowerModel + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + # Expression + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + return +end + +""" +Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractPowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, ReactivePowerVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractPowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_constraints!( + container, + ReactivePowerVariableLimitsConstraint, + ReactivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + add_constraint_dual!(container, sys, model) + + return +end + +""" +Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation +with only Active Power. +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end + +""" +Construct model for HydroGen with RunOfRiver Commitment Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, ReactivePowerVariable, devices, D()) + add_variables!(container, OnVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_constraints!( + container, + ReactivePowerVariableLimitsConstraint, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end + +""" +Construct model for HydroGen with RunOfRiver Commitment Formulation +with only Active Power. +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: HydroCommitmentRunOfRiver, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, OnVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: HydroCommitmentRunOfRiver, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl new file mode 100644 index 0000000000..69e861b2c7 --- /dev/null +++ b/src/devices_models/devices/hydro_generation.jl @@ -0,0 +1,297 @@ +#! format: off +requires_initialization(::AbstractHydroFormulation) = false +requires_initialization(::AbstractHydroUnitCommitment) = true + +get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 +get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB +get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB + +########################### ActivePowerVariable, HydroGen ################################# +get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false +get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 +get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max + +############## ActivePowerVariable, HydroDispatchRunOfRiver #################### +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 + +############## ReactivePowerVariable, HydroGen #################### +get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false +get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power(d) +get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).min +get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).max + +############## OnVariable, HydroGen #################### +get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true +get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 + +########################### Parameter related set functions ################################ +get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) +get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) + +get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 +get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 +get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max +get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min + +#################### Initial Conditions for models ############### +initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) +initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() +initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) +initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() +initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 +initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() +initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) +initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() + +########################Objective Function################################################## +proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 +proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) +proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_surplus_cost(cost) +proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_shortage_cost(cost) + +objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::EnergySurplusVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_NEGATIVE +objective_function_multiplier(::EnergyShortageVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE + +sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE +sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE + +variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 +variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) +variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) + +#! format: on + +function get_initial_conditions_device_model( + ::OperationModel, + model::DeviceModel{T, <:AbstractHydroFormulation}, +) where {T <: PSY.HydroEnergyReservoir} + return model +end + +function get_initial_conditions_device_model( + ::OperationModel, + ::DeviceModel{T, <:AbstractHydroFormulation}, +) where {T <: PSY.HydroDispatch} + return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) +end + +function get_default_time_series_names( + ::Type{<:PSY.HydroGen}, + ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, +) + return Dict{Type{<:TimeSeriesParameter}, String}( + ActivePowerTimeSeriesParameter => "max_active_power", + ReactivePowerTimeSeriesParameter => "max_active_power", + ) +end + +function get_default_attributes( + ::Type{T}, + ::Type{D}, +) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} + return Dict{String, Any}("reservation" => false) +end + +""" +Time series constraints +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + add_parameterized_upper_bound_range_constraints( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + U, + ActivePowerTimeSeriesParameter, + devices, + model, + X, + ) + return +end + +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:RangeConstraintLBExpressions}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + return +end + +""" +Add semicontinuous range constraints for Hydro Unit Commitment formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + return +end + +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + add_parameterized_upper_bound_range_constraints( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + U, + ActivePowerTimeSeriesParameter, + devices, + model, + X, + ) + return +end + +""" +Min and max reactive Power Variable limits +""" +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ReactivePowerVariableLimitsConstraint}, + ::Type{<:AbstractHydroFormulation}, +) + return PSY.get_reactive_power_limits(x) +end + +""" +Min and max active Power Variable limits +""" +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ActivePowerVariableLimitsConstraint}, + ::Type{<:AbstractHydroFormulation}, +) + return PSY.get_active_power_limits(x) +end + +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ActivePowerVariableLimitsConstraint}, + ::Type{HydroDispatchRunOfRiver}, +) + return (min = 0.0, max = PSY.get_max_active_power(x)) +end + +""" +Add power variable limits constraints for hydro unit commitment formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{<:PowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + return +end + +""" +Add power variable limits constraints for hydro dispatch formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{<:PowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where { + V <: PSY.HydroGen, + W <: AbstractHydroDispatchFormulation, + X <: PM.AbstractPowerModel, +} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + return +end + +##################################### Auxillary Variables ############################ +function _calculate_aux_variable_value!( + container::OptimizationContainer, + ::AuxVarKey{EnergyOutput, T}, + system::PSY.System, + p_variable_results::JuMPVariableArray, +) where {T <: PSY.HydroGen} + devices = axes(p_variable_results, 1) + time_steps = get_time_steps(container) + resolution = get_resolution(container) + fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR + aux_variable_container = get_aux_variable(container, EnergyOutput(), T) + for name in devices, t in time_steps + aux_variable_container[name, t] = + jump_value(p_variable_results[name, t]) * fraction_of_hour + end + + return +end + +function calculate_aux_variable_value!( + container::OptimizationContainer, + aux_key::AuxVarKey{EnergyOutput, T}, + system::PSY.System, +) where {T <: PSY.HydroGen} + p_variable_results = get_variable(container, ActivePowerVariable(), T) + _calculate_aux_variable_value!( + container, + aux_key, + system, + p_variable_results, + ) + return +end + +##################################### Hydro generation cost ############################ +function objective_function!( + container::OptimizationContainer, + devices::IS.FlattenIteratorWrapper{T}, + ::DeviceModel{T, U}, + ::Type{<:PM.AbstractPowerModel}, +) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} + add_variable_cost!(container, ActivePowerVariable(), devices, U()) + add_proportional_cost!(container, OnVariable(), devices, U()) + return +end + +function objective_function!( + container::OptimizationContainer, + devices::IS.FlattenIteratorWrapper{T}, + ::DeviceModel{T, U}, + ::Type{<:PM.AbstractPowerModel}, +) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} + add_variable_cost!(container, ActivePowerVariable(), devices, U()) + return +end From f23ace1bb32b6cfc490158971617b07f7ceb06e5 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:42 -0700 Subject: [PATCH 122/370] bring back hydro tests --- ...st_device_hydro_generation_constructors.jl | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 test/test_device_hydro_generation_constructors.jl diff --git a/test/test_device_hydro_generation_constructors.jl b/test/test_device_hydro_generation_constructors.jl new file mode 100644 index 0000000000..7545c57ace --- /dev/null +++ b/test/test_device_hydro_generation_constructors.jl @@ -0,0 +1,121 @@ +################################### +###### FIXED OUTPUT TESTS ######### +################################### + +@testset "Hydro DCPLossLess FixedOutput" begin + device_model = DeviceModel(HydroDispatch, FixedOutput) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 0, 0, 0, 0, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with FixedOutput formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, FixedOutput) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 0, 0, 0, 0, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +################################### +### RUN OF RIVER DISPATCH TESTS ### +################################### + +@testset "Hydro DCPLossLess HydroDispatch with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 24, 0, 48, 24, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroDispatch with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 72, 48, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 24, 0, 48, 24, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 72, 48, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +################################### +#### RUN OF RIVER COMMIT TESTS #### +################################### + +@testset "Hydro DCPLossLess HydroDispatch with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 48, 24, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroDispatch with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 72, 0, 72, 48, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 48, 24, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 72, 0, 72, 48, 0, true) + psi_checkobjfun_test(model, GAEVF) +end From b5e218298795e9692069d35de8688f789644f67b Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:57 -0700 Subject: [PATCH 123/370] remove reservoir budget from tests --- test/test_model_decision.jl | 62 ------------------ test/test_model_emulation.jl | 104 ------------------------------ test/test_print.jl | 7 -- test/test_services_constructor.jl | 23 +++++++ test/test_simulation_build.jl | 1 - test/test_simulation_execute.jl | 14 ---- test/test_simulation_results.jl | 11 +--- 7 files changed, 25 insertions(+), 197 deletions(-) diff --git a/test/test_model_decision.jl b/test/test_model_decision.jl index 12f3cb8074..3af76fc801 100644 --- a/test/test_model_decision.jl +++ b/test/test_model_decision.jl @@ -488,68 +488,6 @@ end HydroEnergyReservoir, ) @test solve!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroDispatchReservoirBudget ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; force_build = true) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirBudget) - model = DecisionModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test !PSI.has_initial_condition_value( - initial_conditions_data, - ActivePowerVariable(), - HydroEnergyReservoir, - ) - @test solve!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentReservoirBudget ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; force_build = true) - set_device_model!(template, HydroEnergyReservoir, HydroCommitmentReservoirBudget) - model = DecisionModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test PSI.has_initial_condition_value( - initial_conditions_data, - OnVariable(), - HydroEnergyReservoir, - ) - @test solve!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroDispatchReservoirStorage ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems"; force_build = true) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - model = DecisionModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test !PSI.has_initial_condition_value( - initial_conditions_data, - ActivePowerVariable(), - HydroEnergyReservoir, - ) - check_energy_initial_conditions_values(model, HydroEnergyReservoir) - @test solve!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentReservoirStorage ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems"; force_build = true) - set_device_model!(template, HydroEnergyReservoir, HydroCommitmentReservoirStorage) - model = DecisionModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test PSI.has_initial_condition_value( - initial_conditions_data, - OnVariable(), - HydroEnergyReservoir, - ) - check_energy_initial_conditions_values(model, HydroEnergyReservoir) - @test solve!(model) == RunStatus.SUCCESSFUL end @testset "Test serialization of InitialConditionsData" begin diff --git a/test/test_model_emulation.jl b/test/test_model_emulation.jl index ba40caa9ba..06baefcf7f 100644 --- a/test/test_model_emulation.jl +++ b/test/test_model_emulation.jl @@ -142,110 +142,6 @@ end HydroEnergyReservoir, ) @test run!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentRunOfRiver ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system( - PSITestSystems, - "c_sys5_hyd"; - add_single_time_series = true, - force_build = true, - ) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirBudget) - model = EmulationModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; executions = 10, output_dir = mktempdir(; cleanup = true)) == - BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test !PSI.has_initial_condition_value( - initial_conditions_data, - ActivePowerVariable(), - HydroEnergyReservoir, - ) - @test run!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentRunOfRiver ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system( - PSITestSystems, - "c_sys5_hyd"; - add_single_time_series = true, - force_build = true, - ) - set_device_model!(template, HydroEnergyReservoir, HydroCommitmentReservoirBudget) - model = EmulationModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; executions = 10, output_dir = mktempdir(; cleanup = true)) == - BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test PSI.has_initial_condition_value( - initial_conditions_data, - OnVariable(), - HydroEnergyReservoir, - ) - @test run!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentRunOfRiver ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system( - PSITestSystems, - "c_sys5_hyd_ems"; - add_single_time_series = true, - force_build = true, - ) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - model = EmulationModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; executions = 10, output_dir = mktempdir(; cleanup = true)) == - BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test !PSI.has_initial_condition_value( - initial_conditions_data, - ActivePowerVariable(), - HydroEnergyReservoir, - ) - ic_data = PSI.get_initial_condition( - PSI.get_optimization_container(model), - InitialEnergyLevel(), - HydroEnergyReservoir, - ) - for ic in ic_data - name = PSY.get_name(ic.component) - e_var = PSI.jump_value(PSI.get_value(ic)) - @test PSY.get_initial_storage(ic.component) == e_var - end - @test run!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentRunOfRiver ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system( - PSITestSystems, - "c_sys5_hyd_ems"; - add_single_time_series = true, - force_build = true, - ) - set_device_model!(template, HydroEnergyReservoir, HydroCommitmentReservoirStorage) - model = EmulationModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; executions = 10, output_dir = mktempdir(; cleanup = true)) == - BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test PSI.has_initial_condition_value( - initial_conditions_data, - OnVariable(), - HydroEnergyReservoir, - ) - ic_data = PSI.get_initial_condition( - PSI.get_optimization_container(model), - InitialEnergyLevel(), - HydroEnergyReservoir, - ) - for ic in ic_data - name = PSY.get_name(ic.component) - e_var = PSI.jump_value(PSI.get_value(ic)) - @test PSY.get_initial_storage(ic.component) == e_var - end - @test run!(model) == RunStatus.SUCCESSFUL end @testset "Emulation Model Results" begin diff --git a/test/test_print.jl b/test/test_print.jl index 43c154d02a..ff1e6108ea 100644 --- a/test/test_print.jl +++ b/test/test_print.jl @@ -45,7 +45,6 @@ end template_uc = get_template_basic_uc_simulation() template_ed = get_template_nomin_ed_simulation() set_device_model!(template_ed, InterruptiblePowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchReservoirBudget) set_network_model!(template_uc, NetworkModel( CopperPlatePowerModel, # MILP "duals" not supported with free solvers @@ -88,12 +87,6 @@ end source = OnVariable, affected_values = [ActivePowerVariable], ), - EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ), ], ), ini_cond_chronology = InterProblemChronology(), diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index c264dd41ac..9c4100a19c 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -132,6 +132,29 @@ end moi_tests(model, 360, 0, 72, 120, 72, false) end +@testset "Test Reserves from Hydro" begin + template = ProblemTemplate(CopperPlatePowerModel) + set_device_model!(template, PowerLoad, StaticPowerLoad) + set_device_model!(template, HydroEnergyReservoir, HydroDispatchRunOfRiver) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve5"), + ) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveDown}, RangeReserve, "Reserve6"), + ) + set_service_model!( + template, + ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), + ) + + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; add_reserves = true) + model = DecisionModel(template, c_sys5_hyd) + @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT + moi_tests(model, 240, 0, 48, 96, 72, false) +end + @testset "Test Reserves from with slack variables" begin template = get_thermal_dispatch_template_network( NetworkModel(CopperPlatePowerModel; use_slacks = true), diff --git a/test/test_simulation_build.jl b/test/test_simulation_build.jl index b2fbe6589d..5bda0fa750 100644 --- a/test/test_simulation_build.jl +++ b/test/test_simulation_build.jl @@ -132,7 +132,6 @@ end @test_throws IS.ConflictingInputsError PSI._check_folder(sim) end - @testset "Test SemiContinuous Feedforward with Active and Reactive Power variables" begin template_uc = get_template_basic_uc_simulation() set_network_model!(template_uc, NetworkModel(DCPPowerModel; use_slacks = true)) diff --git a/test/test_simulation_execute.jl b/test/test_simulation_execute.jl index 783c4c5241..f50bab178f 100644 --- a/test/test_simulation_execute.jl +++ b/test/test_simulation_execute.jl @@ -38,7 +38,6 @@ function test_2_stage_decision_models_with_feedforwards(in_memory) template_uc = get_template_basic_uc_simulation() template_ed = get_template_nomin_ed_simulation() set_device_model!(template_ed, InterruptiblePowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchReservoirBudget) set_network_model!(template_uc, NetworkModel( CopperPlatePowerModel, # MILP "duals" not supported with free solvers @@ -80,12 +79,6 @@ function test_2_stage_decision_models_with_feedforwards(in_memory) source = OnVariable, affected_values = [ActivePowerVariable], ), - EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ), ], ), ini_cond_chronology = InterProblemChronology(), @@ -128,7 +121,6 @@ end ), ) set_device_model!(template_ed, InterruptiblePowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchReservoirBudget) c_sys5_hy_uc = PSB.build_system(PSITestSystems, "c_sys5_hy_uc") c_sys5_hy_ed = PSB.build_system(PSITestSystems, "c_sys5_hy_ed") models = SimulationModels(; @@ -157,12 +149,6 @@ end source = OnVariable, affected_values = [ActivePowerVariable], ), - EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ), ], ), ini_cond_chronology = InterProblemChronology(), diff --git a/test/test_simulation_results.jl b/test/test_simulation_results.jl index 98525c9302..4b8816d043 100644 --- a/test/test_simulation_results.jl +++ b/test/test_simulation_results.jl @@ -132,7 +132,6 @@ function test_simulation_results(file_path::String, export_path; in_memory = fal template_uc = get_template_basic_uc_simulation() template_ed = get_template_nomin_ed_simulation() set_device_model!(template_ed, InterruptiblePowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchReservoirBudget) set_network_model!( template_uc, NetworkModel(CopperPlatePowerModel; duals = [CopperPlateBalanceConstraint]), @@ -173,12 +172,6 @@ function test_simulation_results(file_path::String, export_path; in_memory = fal source = OnVariable, affected_values = [ActivePowerVariable], ), - EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ), ], ), ini_cond_chronology = InterProblemChronology(), @@ -230,7 +223,7 @@ function test_simulation_results(file_path::String, export_path; in_memory = fal verify_export_results(results, export_path) - @test length(readdir(export_realized_results(results_ed))) === 18 + @test length(readdir(export_realized_results(results_ed))) === 17 # Test that you can't read a failed simulation. PSI.set_simulation_status!(sim, RunStatus.FAILED) @@ -547,7 +540,7 @@ function test_emulation_problem_results(results::SimulationResults, in_memory) ) == 10 parameters_keys = collect(keys(read_realized_parameters(results_em))) - @test length(parameters_keys) == 7 + @test length(parameters_keys) == 5 parameters_inputs = ( [ "ActivePowerTimeSeriesParameter__PowerLoad", From efddb31ee3b87387ef66bf7ebb2c3ffdd87e211d Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 13:04:52 -0700 Subject: [PATCH 124/370] bring back hydro docs --- docs/make.jl | 1 + docs/src/formulation_library/General.md | 2 +- docs/src/formulation_library/HydroGen.md | 134 +++++++++++++++++++++++ 3 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 docs/src/formulation_library/HydroGen.md diff --git a/docs/make.jl b/docs/make.jl index f2ec3aaedb..0fc90a93a8 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -30,6 +30,7 @@ pages = OrderedDict( "Formulation Library" => Any[ "General" => "formulation_library/General.md", "Thermal Generation" => "formulation_library/ThermalGen.md", + "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", diff --git a/docs/src/formulation_library/General.md b/docs/src/formulation_library/General.md index 8b69c0803a..e5912b268c 100644 --- a/docs/src/formulation_library/General.md +++ b/docs/src/formulation_library/General.md @@ -29,7 +29,7 @@ using PowerSystems using DataFrames using Latexify combo_tables = [] -for t in [RenewableGen, ThermalGen, ElectricLoad] +for t in [RenewableGen, ThermalGen, HydroGen, ElectricLoad] combos = PowerSimulations.get_default_time_series_names(t, FixedOutput) combo_table = DataFrame( "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md new file mode 100644 index 0000000000..efe13982b3 --- /dev/null +++ b/docs/src/formulation_library/HydroGen.md @@ -0,0 +1,134 @@ +# `PowerSystems.HydroGen` Formulations + +Valid `DeviceModel`s for subtypes of `HydroGen` include the following: + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.generate_device_formulation_combinations() +filter!(x -> x["device_type"] <: HydroGen, combos) +combo_table = DataFrame( + "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], + "Device Type" => ["[$(c["device_type"])](https://nrel-siip.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], + "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], + ) +mdtable(combo_table, latex = false) +``` + +--- + +## `HydroDispatchRunOfRiver` + +```@docs +HydroDispatchRunOfRiver +``` + +**Variables:** + +- [`ActivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_active_power(device)` +- [`ReactivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_reactive_power(device)` + +**Static Parameters:** + +- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` +- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` +- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` + +**Time Series Parameters:** + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroDispatchRunOfRiver) +combo_table = DataFrame( + "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), + "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), + ) +mdtable(combo_table, latex = false) +``` + +**Objective:** + +Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg``. + +**Expressions:** + +Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) + +**Constraints:** + +```math +\begin{aligned} +& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ +& Qg^\text{min} \le Qg_t \le Qg^\text{max} +\end{aligned} +``` + +--- + +## `HydroCommitmentRunOfRiver` + +```@docs +HydroCommitmentRunOfRiver +``` + +**Variables:** + +- [`ActivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_active_power(device)` +- [`ReactivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_reactive_power(device)` +- [`OnVariable`](@ref): + - Bounds: {0, 1} + - Default initial value: `PowerSystems.get_status(device)` + +**Static Parameters:** + +- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` +- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` +- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` + +**Time Series Parameters:** + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroCommitmentRunOfRiver) +combo_table = DataFrame( + "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), + "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), + ) +mdtable(combo_table, latex = false) +``` + +**Objective:** + +Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. + +**Expressions:** + +Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) + +**Constraints:** + +```math +\begin{aligned} +& Pg_t \le Pg^\text{max}\\ +& Pg_t - u_t Pg^\text{max} \le 0 \\ +& Pg_t - u_t Pg^\text{min} \ge 0 \\ +& Qg_t - u_t Qg^\text{max} \le 0 \\ +& Qg_t - u_t Qg^\text{min} \ge 0 +\end{aligned} +``` \ No newline at end of file From 940830979d2a2e13d9ea052cbc45bd5d00ade11b Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 7 Jul 2023 12:47:04 -0600 Subject: [PATCH 125/370] remove code --- docs/make.jl | 1 - docs/src/formulation_library/General.md | 2 +- docs/src/formulation_library/HydroGen.md | 134 ----- src/core/formulations.jl | 7 - .../hydrogeneration_constructor.jl | 468 ------------------ .../devices/hydro_generation.jl | 297 ----------- ...st_device_hydro_generation_constructors.jl | 121 ----- test/test_services_constructor.jl | 23 - 8 files changed, 1 insertion(+), 1052 deletions(-) delete mode 100644 docs/src/formulation_library/HydroGen.md delete mode 100644 src/devices_models/device_constructors/hydrogeneration_constructor.jl delete mode 100644 src/devices_models/devices/hydro_generation.jl delete mode 100644 test/test_device_hydro_generation_constructors.jl diff --git a/docs/make.jl b/docs/make.jl index 0fc90a93a8..f2ec3aaedb 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -30,7 +30,6 @@ pages = OrderedDict( "Formulation Library" => Any[ "General" => "formulation_library/General.md", "Thermal Generation" => "formulation_library/ThermalGen.md", - "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", diff --git a/docs/src/formulation_library/General.md b/docs/src/formulation_library/General.md index e5912b268c..8b69c0803a 100644 --- a/docs/src/formulation_library/General.md +++ b/docs/src/formulation_library/General.md @@ -29,7 +29,7 @@ using PowerSystems using DataFrames using Latexify combo_tables = [] -for t in [RenewableGen, ThermalGen, HydroGen, ElectricLoad] +for t in [RenewableGen, ThermalGen, ElectricLoad] combos = PowerSimulations.get_default_time_series_names(t, FixedOutput) combo_table = DataFrame( "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md deleted file mode 100644 index efe13982b3..0000000000 --- a/docs/src/formulation_library/HydroGen.md +++ /dev/null @@ -1,134 +0,0 @@ -# `PowerSystems.HydroGen` Formulations - -Valid `DeviceModel`s for subtypes of `HydroGen` include the following: - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.generate_device_formulation_combinations() -filter!(x -> x["device_type"] <: HydroGen, combos) -combo_table = DataFrame( - "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], - "Device Type" => ["[$(c["device_type"])](https://nrel-siip.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], - "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], - ) -mdtable(combo_table, latex = false) -``` - ---- - -## `HydroDispatchRunOfRiver` - -```@docs -HydroDispatchRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroDispatchRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} -\end{aligned} -``` - ---- - -## `HydroCommitmentRunOfRiver` - -```@docs -HydroCommitmentRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroCommitmentRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg_t \le Pg^\text{max}\\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` \ No newline at end of file diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 7522280c51..948289a0e0 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -74,19 +74,12 @@ struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end ############################ Hydro Generation Formulations ################################# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end -abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end -abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end -""" -Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` -""" -struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end - ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end struct ReserveLimitedRegulation <: AbstractRegulationFormulation end diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl deleted file mode 100644 index 75673eba77..0000000000 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ /dev/null @@ -1,468 +0,0 @@ -""" -Construct model for HydroGen with FixedOutput Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -function construct_device!( - ::OptimizationContainer, - ::PSY.System, - ::ModelConstructStage, - ::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - # FixedOutput doesn't add any constraints to the model. This function covers - # AbstractPowerModel and AbstractActivePowerModel - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -""" -Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl deleted file mode 100644 index 69e861b2c7..0000000000 --- a/src/devices_models/devices/hydro_generation.jl +++ /dev/null @@ -1,297 +0,0 @@ -#! format: off -requires_initialization(::AbstractHydroFormulation) = false -requires_initialization(::AbstractHydroUnitCommitment) = true - -get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB - -########################### ActivePowerVariable, HydroGen ################################# -get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 -get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max - -############## ActivePowerVariable, HydroDispatchRunOfRiver #################### -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 - -############## ReactivePowerVariable, HydroGen #################### -get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power(d) -get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).min -get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).max - -############## OnVariable, HydroGen #################### -get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true -get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 - -########################### Parameter related set functions ################################ -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) - -get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min - -#################### Initial Conditions for models ############### -initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) -initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() -initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 -initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) -initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() - -########################Objective Function################################################## -proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 -proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_surplus_cost(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_shortage_cost(cost) - -objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::EnergySurplusVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_NEGATIVE -objective_function_multiplier(::EnergyShortageVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE - -sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE -sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE - -variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 -variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) -variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) - -#! format: on - -function get_initial_conditions_device_model( - ::OperationModel, - model::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroEnergyReservoir} - return model -end - -function get_initial_conditions_device_model( - ::OperationModel, - ::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroDispatch} - return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) -end - -function get_default_time_series_names( - ::Type{<:PSY.HydroGen}, - ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - ActivePowerTimeSeriesParameter => "max_active_power", - ReactivePowerTimeSeriesParameter => "max_active_power", - ) -end - -function get_default_attributes( - ::Type{T}, - ::Type{D}, -) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} - return Dict{String, Any}("reservation" => false) -end - -""" -Time series constraints -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:RangeConstraintLBExpressions}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -""" -Add semicontinuous range constraints for Hydro Unit Commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -""" -Min and max reactive Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ReactivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_reactive_power_limits(x) -end - -""" -Min and max active Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_active_power_limits(x) -end - -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchRunOfRiver}, -) - return (min = 0.0, max = PSY.get_max_active_power(x)) -end - -""" -Add power variable limits constraints for hydro unit commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -""" -Add power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroGen, - W <: AbstractHydroDispatchFormulation, - X <: PM.AbstractPowerModel, -} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -##################################### Auxillary Variables ############################ -function _calculate_aux_variable_value!( - container::OptimizationContainer, - ::AuxVarKey{EnergyOutput, T}, - system::PSY.System, - p_variable_results::JuMPVariableArray, -) where {T <: PSY.HydroGen} - devices = axes(p_variable_results, 1) - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - aux_variable_container = get_aux_variable(container, EnergyOutput(), T) - for name in devices, t in time_steps - aux_variable_container[name, t] = - jump_value(p_variable_results[name, t]) * fraction_of_hour - end - - return -end - -function calculate_aux_variable_value!( - container::OptimizationContainer, - aux_key::AuxVarKey{EnergyOutput, T}, - system::PSY.System, -) where {T <: PSY.HydroGen} - p_variable_results = get_variable(container, ActivePowerVariable(), T) - _calculate_aux_variable_value!( - container, - aux_key, - system, - p_variable_results, - ) - return -end - -##################################### Hydro generation cost ############################ -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, OnVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - return -end diff --git a/test/test_device_hydro_generation_constructors.jl b/test/test_device_hydro_generation_constructors.jl deleted file mode 100644 index 7545c57ace..0000000000 --- a/test/test_device_hydro_generation_constructors.jl +++ /dev/null @@ -1,121 +0,0 @@ -################################### -###### FIXED OUTPUT TESTS ######### -################################### - -@testset "Hydro DCPLossLess FixedOutput" begin - device_model = DeviceModel(HydroDispatch, FixedOutput) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with FixedOutput formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, FixedOutput) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -### RUN OF RIVER DISPATCH TESTS ### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -#### RUN OF RIVER COMMIT TESTS #### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index 9c4100a19c..c264dd41ac 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -132,29 +132,6 @@ end moi_tests(model, 360, 0, 72, 120, 72, false) end -@testset "Test Reserves from Hydro" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, PowerLoad, StaticPowerLoad) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchRunOfRiver) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve5"), - ) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveDown}, RangeReserve, "Reserve6"), - ) - set_service_model!( - template, - ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), - ) - - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; add_reserves = true) - model = DecisionModel(template, c_sys5_hyd) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 240, 0, 48, 96, 72, false) -end - @testset "Test Reserves from with slack variables" begin template = get_thermal_dispatch_template_network( NetworkModel(CopperPlatePowerModel; use_slacks = true), From a03a67d80c9306d6c8bc42ff3f03c49296f62f47 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 25 Apr 2023 13:59:51 -0600 Subject: [PATCH 126/370] move more code --- src/PowerSimulations.jl | 3 --- src/core/formulations.jl | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 41a1f0c63b..f2c45c3dd4 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -69,7 +69,6 @@ export ReserveLimitedRegulation ###### Hydro ####### export HydroDispatchRunOfRiver -export HydroCommitmentRunOfRiver # feedforward models export UpperBoundFeedforward @@ -529,7 +528,6 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") -include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") # Services Models @@ -551,7 +549,6 @@ include("initial_conditions/initialization.jl") # Device constructors include("devices_models/device_constructors/constructor_validations.jl") include("devices_models/device_constructors/thermalgeneration_constructor.jl") -include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 948289a0e0..4916aef959 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -78,7 +78,7 @@ abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ -struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end +struct HydroDispatchRunOfRiver <: AbstractHydroFormulation end ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end From fba5f65e9734de33e196042917c5c53f04f89fe8 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 24 Apr 2023 16:23:32 -0600 Subject: [PATCH 127/370] remove code --- test/test_services_constructor.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index c264dd41ac..f0ba76db4a 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -129,7 +129,7 @@ end c_sys5_re = PSB.build_system(PSITestSystems, "c_sys5_re"; add_reserves = true) model = DecisionModel(template, c_sys5_re) @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 360, 0, 72, 120, 72, false) + moi_tests(model, 360, 0, 72, 48, 72, false) end @testset "Test Reserves from with slack variables" begin From 0f7395b715518596cd9a3a4cedf260b6bb4c1242 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:35 -0700 Subject: [PATCH 128/370] bring back hydro constructors --- src/PowerSimulations.jl | 3 + src/core/formulations.jl | 9 +- .../hydrogeneration_constructor.jl | 468 ++++++++++++++++++ .../devices/hydro_generation.jl | 297 +++++++++++ 4 files changed, 776 insertions(+), 1 deletion(-) create mode 100644 src/devices_models/device_constructors/hydrogeneration_constructor.jl create mode 100644 src/devices_models/devices/hydro_generation.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index f2c45c3dd4..41a1f0c63b 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -69,6 +69,7 @@ export ReserveLimitedRegulation ###### Hydro ####### export HydroDispatchRunOfRiver +export HydroCommitmentRunOfRiver # feedforward models export UpperBoundFeedforward @@ -528,6 +529,7 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") +include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") # Services Models @@ -549,6 +551,7 @@ include("initial_conditions/initialization.jl") # Device constructors include("devices_models/device_constructors/constructor_validations.jl") include("devices_models/device_constructors/thermalgeneration_constructor.jl") +include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 4916aef959..7522280c51 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -74,11 +74,18 @@ struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end ############################ Hydro Generation Formulations ################################# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end +abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end +abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ -struct HydroDispatchRunOfRiver <: AbstractHydroFormulation end +struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end + +""" +Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` +""" +struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl new file mode 100644 index 0000000000..75673eba77 --- /dev/null +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -0,0 +1,468 @@ +""" +Construct model for HydroGen with FixedOutput Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) + + # Expression + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + return +end + +function construct_device!( + ::OptimizationContainer, + ::PSY.System, + ::ModelConstructStage, + ::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} + # FixedOutput doesn't add any constraints to the model. This function covers + # AbstractPowerModel and AbstractActivePowerModel + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + # Expression + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + return +end + +""" +Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractPowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, ReactivePowerVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractPowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_constraints!( + container, + ReactivePowerVariableLimitsConstraint, + ReactivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + add_constraint_dual!(container, sys, model) + + return +end + +""" +Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation +with only Active Power. +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end + +""" +Construct model for HydroGen with RunOfRiver Commitment Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, ReactivePowerVariable, devices, D()) + add_variables!(container, OnVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_constraints!( + container, + ReactivePowerVariableLimitsConstraint, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end + +""" +Construct model for HydroGen with RunOfRiver Commitment Formulation +with only Active Power. +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: HydroCommitmentRunOfRiver, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, OnVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: HydroCommitmentRunOfRiver, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl new file mode 100644 index 0000000000..69e861b2c7 --- /dev/null +++ b/src/devices_models/devices/hydro_generation.jl @@ -0,0 +1,297 @@ +#! format: off +requires_initialization(::AbstractHydroFormulation) = false +requires_initialization(::AbstractHydroUnitCommitment) = true + +get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 +get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB +get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB + +########################### ActivePowerVariable, HydroGen ################################# +get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false +get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 +get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max + +############## ActivePowerVariable, HydroDispatchRunOfRiver #################### +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 + +############## ReactivePowerVariable, HydroGen #################### +get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false +get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power(d) +get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).min +get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).max + +############## OnVariable, HydroGen #################### +get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true +get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 + +########################### Parameter related set functions ################################ +get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) +get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) + +get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 +get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 +get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max +get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min + +#################### Initial Conditions for models ############### +initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) +initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() +initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) +initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() +initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 +initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() +initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) +initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() + +########################Objective Function################################################## +proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 +proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) +proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_surplus_cost(cost) +proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_shortage_cost(cost) + +objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::EnergySurplusVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_NEGATIVE +objective_function_multiplier(::EnergyShortageVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE + +sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE +sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE + +variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 +variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) +variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) + +#! format: on + +function get_initial_conditions_device_model( + ::OperationModel, + model::DeviceModel{T, <:AbstractHydroFormulation}, +) where {T <: PSY.HydroEnergyReservoir} + return model +end + +function get_initial_conditions_device_model( + ::OperationModel, + ::DeviceModel{T, <:AbstractHydroFormulation}, +) where {T <: PSY.HydroDispatch} + return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) +end + +function get_default_time_series_names( + ::Type{<:PSY.HydroGen}, + ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, +) + return Dict{Type{<:TimeSeriesParameter}, String}( + ActivePowerTimeSeriesParameter => "max_active_power", + ReactivePowerTimeSeriesParameter => "max_active_power", + ) +end + +function get_default_attributes( + ::Type{T}, + ::Type{D}, +) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} + return Dict{String, Any}("reservation" => false) +end + +""" +Time series constraints +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + add_parameterized_upper_bound_range_constraints( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + U, + ActivePowerTimeSeriesParameter, + devices, + model, + X, + ) + return +end + +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:RangeConstraintLBExpressions}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + return +end + +""" +Add semicontinuous range constraints for Hydro Unit Commitment formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + return +end + +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + add_parameterized_upper_bound_range_constraints( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + U, + ActivePowerTimeSeriesParameter, + devices, + model, + X, + ) + return +end + +""" +Min and max reactive Power Variable limits +""" +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ReactivePowerVariableLimitsConstraint}, + ::Type{<:AbstractHydroFormulation}, +) + return PSY.get_reactive_power_limits(x) +end + +""" +Min and max active Power Variable limits +""" +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ActivePowerVariableLimitsConstraint}, + ::Type{<:AbstractHydroFormulation}, +) + return PSY.get_active_power_limits(x) +end + +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ActivePowerVariableLimitsConstraint}, + ::Type{HydroDispatchRunOfRiver}, +) + return (min = 0.0, max = PSY.get_max_active_power(x)) +end + +""" +Add power variable limits constraints for hydro unit commitment formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{<:PowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + return +end + +""" +Add power variable limits constraints for hydro dispatch formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{<:PowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where { + V <: PSY.HydroGen, + W <: AbstractHydroDispatchFormulation, + X <: PM.AbstractPowerModel, +} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + return +end + +##################################### Auxillary Variables ############################ +function _calculate_aux_variable_value!( + container::OptimizationContainer, + ::AuxVarKey{EnergyOutput, T}, + system::PSY.System, + p_variable_results::JuMPVariableArray, +) where {T <: PSY.HydroGen} + devices = axes(p_variable_results, 1) + time_steps = get_time_steps(container) + resolution = get_resolution(container) + fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR + aux_variable_container = get_aux_variable(container, EnergyOutput(), T) + for name in devices, t in time_steps + aux_variable_container[name, t] = + jump_value(p_variable_results[name, t]) * fraction_of_hour + end + + return +end + +function calculate_aux_variable_value!( + container::OptimizationContainer, + aux_key::AuxVarKey{EnergyOutput, T}, + system::PSY.System, +) where {T <: PSY.HydroGen} + p_variable_results = get_variable(container, ActivePowerVariable(), T) + _calculate_aux_variable_value!( + container, + aux_key, + system, + p_variable_results, + ) + return +end + +##################################### Hydro generation cost ############################ +function objective_function!( + container::OptimizationContainer, + devices::IS.FlattenIteratorWrapper{T}, + ::DeviceModel{T, U}, + ::Type{<:PM.AbstractPowerModel}, +) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} + add_variable_cost!(container, ActivePowerVariable(), devices, U()) + add_proportional_cost!(container, OnVariable(), devices, U()) + return +end + +function objective_function!( + container::OptimizationContainer, + devices::IS.FlattenIteratorWrapper{T}, + ::DeviceModel{T, U}, + ::Type{<:PM.AbstractPowerModel}, +) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} + add_variable_cost!(container, ActivePowerVariable(), devices, U()) + return +end From 55d9e3672dedecf0edd5dec3c319e52ff37c44d3 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:42 -0700 Subject: [PATCH 129/370] bring back hydro tests --- ...st_device_hydro_generation_constructors.jl | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 test/test_device_hydro_generation_constructors.jl diff --git a/test/test_device_hydro_generation_constructors.jl b/test/test_device_hydro_generation_constructors.jl new file mode 100644 index 0000000000..7545c57ace --- /dev/null +++ b/test/test_device_hydro_generation_constructors.jl @@ -0,0 +1,121 @@ +################################### +###### FIXED OUTPUT TESTS ######### +################################### + +@testset "Hydro DCPLossLess FixedOutput" begin + device_model = DeviceModel(HydroDispatch, FixedOutput) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 0, 0, 0, 0, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with FixedOutput formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, FixedOutput) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 0, 0, 0, 0, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +################################### +### RUN OF RIVER DISPATCH TESTS ### +################################### + +@testset "Hydro DCPLossLess HydroDispatch with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 24, 0, 48, 24, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroDispatch with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 72, 48, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 24, 0, 48, 24, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 72, 48, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +################################### +#### RUN OF RIVER COMMIT TESTS #### +################################### + +@testset "Hydro DCPLossLess HydroDispatch with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 48, 24, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroDispatch with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 72, 0, 72, 48, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 48, 24, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 72, 0, 72, 48, 0, true) + psi_checkobjfun_test(model, GAEVF) +end From 2b0ac3b98e51fd31d3625d4a30486b409084f17b Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:57 -0700 Subject: [PATCH 130/370] remove reservoir budget from tests --- test/test_services_constructor.jl | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index f0ba76db4a..4fd3a477a1 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -132,6 +132,29 @@ end moi_tests(model, 360, 0, 72, 48, 72, false) end +@testset "Test Reserves from Hydro" begin + template = ProblemTemplate(CopperPlatePowerModel) + set_device_model!(template, PowerLoad, StaticPowerLoad) + set_device_model!(template, HydroEnergyReservoir, HydroDispatchRunOfRiver) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve5"), + ) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveDown}, RangeReserve, "Reserve6"), + ) + set_service_model!( + template, + ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), + ) + + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; add_reserves = true) + model = DecisionModel(template, c_sys5_hyd) + @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT + moi_tests(model, 240, 0, 48, 96, 72, false) +end + @testset "Test Reserves from with slack variables" begin template = get_thermal_dispatch_template_network( NetworkModel(CopperPlatePowerModel; use_slacks = true), From 0d6a61f80bd615d9e30ec8f9cbb743fc302e580f Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 13:04:52 -0700 Subject: [PATCH 131/370] bring back hydro docs --- docs/make.jl | 1 + docs/src/formulation_library/General.md | 2 +- docs/src/formulation_library/HydroGen.md | 134 +++++++++++++++++++++++ 3 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 docs/src/formulation_library/HydroGen.md diff --git a/docs/make.jl b/docs/make.jl index f2ec3aaedb..0fc90a93a8 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -30,6 +30,7 @@ pages = OrderedDict( "Formulation Library" => Any[ "General" => "formulation_library/General.md", "Thermal Generation" => "formulation_library/ThermalGen.md", + "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", diff --git a/docs/src/formulation_library/General.md b/docs/src/formulation_library/General.md index 8b69c0803a..e5912b268c 100644 --- a/docs/src/formulation_library/General.md +++ b/docs/src/formulation_library/General.md @@ -29,7 +29,7 @@ using PowerSystems using DataFrames using Latexify combo_tables = [] -for t in [RenewableGen, ThermalGen, ElectricLoad] +for t in [RenewableGen, ThermalGen, HydroGen, ElectricLoad] combos = PowerSimulations.get_default_time_series_names(t, FixedOutput) combo_table = DataFrame( "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md new file mode 100644 index 0000000000..efe13982b3 --- /dev/null +++ b/docs/src/formulation_library/HydroGen.md @@ -0,0 +1,134 @@ +# `PowerSystems.HydroGen` Formulations + +Valid `DeviceModel`s for subtypes of `HydroGen` include the following: + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.generate_device_formulation_combinations() +filter!(x -> x["device_type"] <: HydroGen, combos) +combo_table = DataFrame( + "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], + "Device Type" => ["[$(c["device_type"])](https://nrel-siip.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], + "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], + ) +mdtable(combo_table, latex = false) +``` + +--- + +## `HydroDispatchRunOfRiver` + +```@docs +HydroDispatchRunOfRiver +``` + +**Variables:** + +- [`ActivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_active_power(device)` +- [`ReactivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_reactive_power(device)` + +**Static Parameters:** + +- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` +- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` +- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` + +**Time Series Parameters:** + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroDispatchRunOfRiver) +combo_table = DataFrame( + "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), + "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), + ) +mdtable(combo_table, latex = false) +``` + +**Objective:** + +Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg``. + +**Expressions:** + +Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) + +**Constraints:** + +```math +\begin{aligned} +& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ +& Qg^\text{min} \le Qg_t \le Qg^\text{max} +\end{aligned} +``` + +--- + +## `HydroCommitmentRunOfRiver` + +```@docs +HydroCommitmentRunOfRiver +``` + +**Variables:** + +- [`ActivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_active_power(device)` +- [`ReactivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_reactive_power(device)` +- [`OnVariable`](@ref): + - Bounds: {0, 1} + - Default initial value: `PowerSystems.get_status(device)` + +**Static Parameters:** + +- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` +- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` +- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` + +**Time Series Parameters:** + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroCommitmentRunOfRiver) +combo_table = DataFrame( + "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), + "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), + ) +mdtable(combo_table, latex = false) +``` + +**Objective:** + +Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. + +**Expressions:** + +Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) + +**Constraints:** + +```math +\begin{aligned} +& Pg_t \le Pg^\text{max}\\ +& Pg_t - u_t Pg^\text{max} \le 0 \\ +& Pg_t - u_t Pg^\text{min} \ge 0 \\ +& Qg_t - u_t Qg^\text{max} \le 0 \\ +& Qg_t - u_t Qg^\text{min} \ge 0 +\end{aligned} +``` \ No newline at end of file From 9b0b2e6f5e16a38a34af86da7d5de6b147d0fb00 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 14 Apr 2023 16:32:50 -0700 Subject: [PATCH 132/370] update docstring for DeviceModel --- src/core/device_model.jl | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/core/device_model.jl b/src/core/device_model.jl index 1e73d2a560..c5749de68c 100644 --- a/src/core/device_model.jl +++ b/src/core/device_model.jl @@ -31,13 +31,16 @@ feedforward to enable passing values between operation model at simulation time # Arguments - - `::Type{D} where D<:PSY.Device`: Power System Device Type - - `::Type{B} where B<:AbstractDeviceFormulation`: Abstract Device Formulation - - `feedforward::Array{<:AbstractAffectFeedforward} = Vector{AbstractAffectFeedforward}()` : use to pass parameters between models - - `use_slacks::Bool = false` : Add slacks to the device model. Implementation is model dependent and not all models feature slacks - - `duals::Vector{DataType} = Vector{DataType}()`: use to pass constraint type to calculate the duals. The DataType needs to be a valid ConstraintType - - `time_series_names::Dict{Type{<:TimeSeriesParameter}, String} = get_default_time_series_names(D, B)` : use to specify time series names associated to the device` - - `attributes::Dict{String, Any} = get_default_attributes(D, B)` : use to specify attributes to the device +-`::Type{D}`: Power System Device Type +-`::Type{B}`: Abstract Device Formulation + +# Accepted Key Words + + - `feedforward::Array{<:AbstractAffectFeedforward}` : use to pass parameters between models + - `use_slacks::Bool : Add slacks to the device model` + - `duals::Vector{DataType} : use to pass constraint type to calculate the duals` + - `time_series_names::Dict{Type{<:TimeSeriesParameter}, String} : use to specify time series names associated to the device` + - `attributes::Dict{String, Any} : use to specify attributes to the device` # Example ```julia From 966e81412249853ac7d48642dcedc7a37f842fc9 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Thu, 20 Apr 2023 17:20:07 -0700 Subject: [PATCH 133/370] update docstrings --- src/core/device_model.jl | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/core/device_model.jl b/src/core/device_model.jl index c5749de68c..078b542927 100644 --- a/src/core/device_model.jl +++ b/src/core/device_model.jl @@ -31,16 +31,13 @@ feedforward to enable passing values between operation model at simulation time # Arguments --`::Type{D}`: Power System Device Type --`::Type{B}`: Abstract Device Formulation - -# Accepted Key Words - - - `feedforward::Array{<:AbstractAffectFeedforward}` : use to pass parameters between models - - `use_slacks::Bool : Add slacks to the device model` - - `duals::Vector{DataType} : use to pass constraint type to calculate the duals` - - `time_series_names::Dict{Type{<:TimeSeriesParameter}, String} : use to specify time series names associated to the device` - - `attributes::Dict{String, Any} : use to specify attributes to the device` + - `::Type{D}`: Power System Device Type + - `::Type{B}`: Abstract Device Formulation + - `feedforward::Array{<:AbstractAffectFeedforward} = Vector{AbstractAffectFeedforward}()` : use to pass parameters between models + - `use_slacks::Bool = false` : Add slacks to the device model + - `duals::Vector{DataType} = Vector{DataType}()`: use to pass constraint type to calculate the duals + - `time_series_names::Dict{Type{<:TimeSeriesParameter}, String} = get_default_time_series_names(D, B)` : use to specify time series names associated to the device` + - `attributes::Dict{String, Any} = get_default_attributes(D, B)` : use to specify attributes to the device # Example ```julia From e6853ff3d4ef9cf35aa1f3ab3c8435922ab7d0b7 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Thu, 20 Apr 2023 17:24:22 -0700 Subject: [PATCH 134/370] add problem templates link --- docs/src/api/PowerSimulations.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index 1ebcfd44ae..c70811fbae 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -34,6 +34,10 @@ Refer to the [Formulations Page](@ref formulation_library) for each Abstract Dev Refer to the [Problem Templates Page](@ref op_problem_template) for available `ProblemTemplate`s. +### Problem Templates + +Refer to the [Problem Templates Page](https://nrel-siip.github.io/PowerSimulations.jl/latest/modeler_guide/problem_templates/) for available `ProblemTemplate`s. + ```@raw html     From e9874e1fb72e830e18bf10e709148ffdb049e5e3 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 21 Apr 2023 13:13:01 -0700 Subject: [PATCH 135/370] add emulation models --- src/core/device_model.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/device_model.jl b/src/core/device_model.jl index 078b542927..7ceb7fda79 100644 --- a/src/core/device_model.jl +++ b/src/core/device_model.jl @@ -31,8 +31,8 @@ feedforward to enable passing values between operation model at simulation time # Arguments - - `::Type{D}`: Power System Device Type - - `::Type{B}`: Abstract Device Formulation + - `::Type{D} where D<:PSY.Device`: Power System Device Type + - `::Type{B} where B<:AbstractDeviceFormulation`: Abstract Device Formulation - `feedforward::Array{<:AbstractAffectFeedforward} = Vector{AbstractAffectFeedforward}()` : use to pass parameters between models - `use_slacks::Bool = false` : Add slacks to the device model - `duals::Vector{DataType} = Vector{DataType}()`: use to pass constraint type to calculate the duals From b0b562bbee525608a88efbc6d322f13c1e073417 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 21 Apr 2023 15:31:26 -0700 Subject: [PATCH 136/370] add variables and constraints --- docs/src/api/PowerSimulations.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index c70811fbae..0c0d669d05 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -102,14 +102,12 @@ execute!(::Simulation) # Variables For a list of variables for each device refer to its Formulations page. - ### Common Variables ```@docs ActivePowerVariable ReactivePowerVariable PieceWiseLinearCostVariable - ``` ### Thermal Unit Variables From dec061db99a264eec0a6fdcb14f206f72648cf24 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Mon, 24 Apr 2023 12:24:28 -0700 Subject: [PATCH 137/370] update common variables --- docs/src/api/PowerSimulations.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index 0c0d669d05..2c935b8d8b 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -136,7 +136,6 @@ ReservationVariable WaterSpillageVariable EnergyVariableUp EnergyVariableDown -EnergyOutput ``` ### Common for Hydro and Storage Variables From 818fcf92b8cdb548fbf90dcff56105983401a135 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 1 May 2023 11:09:35 -0600 Subject: [PATCH 138/370] comment on constraint type --- src/core/device_model.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/device_model.jl b/src/core/device_model.jl index 7ceb7fda79..df17ed64bd 100644 --- a/src/core/device_model.jl +++ b/src/core/device_model.jl @@ -35,7 +35,7 @@ feedforward to enable passing values between operation model at simulation time - `::Type{B} where B<:AbstractDeviceFormulation`: Abstract Device Formulation - `feedforward::Array{<:AbstractAffectFeedforward} = Vector{AbstractAffectFeedforward}()` : use to pass parameters between models - `use_slacks::Bool = false` : Add slacks to the device model - - `duals::Vector{DataType} = Vector{DataType}()`: use to pass constraint type to calculate the duals + - `duals::Vector{DataType} = Vector{DataType}()`: use to pass constraint type to calculate the duals. The DataType needs to be a valid ConstraintType - `time_series_names::Dict{Type{<:TimeSeriesParameter}, String} = get_default_time_series_names(D, B)` : use to specify time series names associated to the device` - `attributes::Dict{String, Any} = get_default_attributes(D, B)` : use to specify attributes to the device From 517215fa0e7eb0a1bf1819b0aa5579d5f71c14dd Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 1 May 2023 11:10:05 -0600 Subject: [PATCH 139/370] slacks clarification --- src/core/device_model.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/device_model.jl b/src/core/device_model.jl index df17ed64bd..1e73d2a560 100644 --- a/src/core/device_model.jl +++ b/src/core/device_model.jl @@ -34,7 +34,7 @@ feedforward to enable passing values between operation model at simulation time - `::Type{D} where D<:PSY.Device`: Power System Device Type - `::Type{B} where B<:AbstractDeviceFormulation`: Abstract Device Formulation - `feedforward::Array{<:AbstractAffectFeedforward} = Vector{AbstractAffectFeedforward}()` : use to pass parameters between models - - `use_slacks::Bool = false` : Add slacks to the device model + - `use_slacks::Bool = false` : Add slacks to the device model. Implementation is model dependent and not all models feature slacks - `duals::Vector{DataType} = Vector{DataType}()`: use to pass constraint type to calculate the duals. The DataType needs to be a valid ConstraintType - `time_series_names::Dict{Type{<:TimeSeriesParameter}, String} = get_default_time_series_names(D, B)` : use to specify time series names associated to the device` - `attributes::Dict{String, Any} = get_default_attributes(D, B)` : use to specify attributes to the device From 6bb2bff39523ff53af6d5ae874b58f44bf2cfce8 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 1 May 2023 11:22:39 -0600 Subject: [PATCH 140/370] rename branch --- README.md | 4 ++++ docs/src/code_base_developer_guide/developer.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/README.md b/README.md index bae459b92e..49f835565d 100644 --- a/README.md +++ b/README.md @@ -54,5 +54,9 @@ Contributions to the development and enhancement of PowerSimulations is welcome. ## License +<<<<<<< HEAD PowerSimulations is released under a BSD [license](https://github.com/NREL-Sienna/PowerSimulations.jl/blob/main/LICENSE). PowerSimulations has been developed as part of the Scalable Integrated Infrastructure Planning (SIIP) +======= +PowerSimulations is released under a BSD [license](https://github.com/NREL/PowerSimulations.jl/blob/main/LICENSE). PowerSimulations has been developed as part of the Scalable Integrated Infrastructure Planning (SIIP) +>>>>>>> 6d7e8ae80 (rename branch) initiative at the U.S. Department of Energy's National Renewable Energy Laboratory ([NREL](https://www.nrel.gov/)) diff --git a/docs/src/code_base_developer_guide/developer.md b/docs/src/code_base_developer_guide/developer.md index b1a859819c..6650449990 100644 --- a/docs/src/code_base_developer_guide/developer.md +++ b/docs/src/code_base_developer_guide/developer.md @@ -4,7 +4,11 @@ In order to contribute to `PowerSystems.jl` repository please read the following [`InfrastructureSystems.jl`](https://github.com/NREL-Sienna/InfrastructureSystems.jl) documentation in detail: +<<<<<<< HEAD 1. [Style Guide](https://nrel-Sienna.github.io/InfrastructureSystems.jl/stable/style/) +======= +1. [Style Guide](https://nrel-siip.github.io/InfrastructureSystems.jl/stable/style/) +>>>>>>> 6d7e8ae80 (rename branch) 2. [Contributing Guidelines](https://github.com/NREL-Sienna/PowerSystems.jl/blob/main/CONTRIBUTING.md) Pull requests are always welcome to fix bugs or add additional modeling capabilities. From 1f7cdc951e9cb3fcf953285158bf27a0c429f1ea Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 1 May 2023 11:50:59 -0600 Subject: [PATCH 141/370] more readme corrections --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 49f835565d..0bb404163a 100644 --- a/README.md +++ b/README.md @@ -54,9 +54,13 @@ Contributions to the development and enhancement of PowerSimulations is welcome. ## License +<<<<<<< HEAD <<<<<<< HEAD PowerSimulations is released under a BSD [license](https://github.com/NREL-Sienna/PowerSimulations.jl/blob/main/LICENSE). PowerSimulations has been developed as part of the Scalable Integrated Infrastructure Planning (SIIP) ======= PowerSimulations is released under a BSD [license](https://github.com/NREL/PowerSimulations.jl/blob/main/LICENSE). PowerSimulations has been developed as part of the Scalable Integrated Infrastructure Planning (SIIP) >>>>>>> 6d7e8ae80 (rename branch) +======= +PowerSimulations is released under a BSD [license](https://github.com/NREL-Sienna/PowerSimulations.jl/blob/main/LICENSE). PowerSimulations has been developed as part of the Scalable Integrated Infrastructure Planning (SIIP) +>>>>>>> 055e20d2b (more readme corrections) initiative at the U.S. Department of Energy's National Renewable Energy Laboratory ([NREL](https://www.nrel.gov/)) From 477fec74e4b9c12b7a108c14ea901f422e36e2f4 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 3 May 2023 00:06:16 -0600 Subject: [PATCH 142/370] add option to pass a second filter function --- src/utils/powersystems_utils.jl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/utils/powersystems_utils.jl b/src/utils/powersystems_utils.jl index 2af80e6319..3e8d29a1a1 100644 --- a/src/utils/powersystems_utils.jl +++ b/src/utils/powersystems_utils.jl @@ -11,6 +11,7 @@ function get_available_components( sys::PSY.System, f::Function, ) where {T <: PSY.Component} +<<<<<<< HEAD return PSY.get_components(x -> PSY.get_available(x) && f(x), T, sys) end @@ -24,6 +25,9 @@ function get_available_components( PSY.Bus, sys, ) +======= + return f(PSY.get_components(PSY.get_available, T, sys)) +>>>>>>> 55415f84d (add option to pass a second filter function) end function get_available_components( From 780b57e6c144ae4d20e8194d73586b40ec8564ca Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 3 May 2023 00:07:08 -0600 Subject: [PATCH 143/370] apply filter in other places --- .../devices/hydro_generation.jl | 31 +------------------ 1 file changed, 1 insertion(+), 30 deletions(-) diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 65792bb3bf..a6f2871ef1 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -707,6 +707,7 @@ function _calculate_aux_variable_value!( system::PSY.System, p_variable_results::JuMPVariableArray, ) where {T <: PSY.HydroGen} + p_variable_results = get_variable(container, ActivePowerVariable(), T) devices = axes(p_variable_results, 1) time_steps = get_time_steps(container) resolution = get_resolution(container) @@ -720,36 +721,6 @@ function _calculate_aux_variable_value!( return end -function calculate_aux_variable_value!( - container::OptimizationContainer, - aux_key::AuxVarKey{EnergyOutput, T}, - system::PSY.System, -) where {T <: PSY.HydroGen} - p_variable_results = get_variable(container, ActivePowerVariable(), T) - _calculate_aux_variable_value!( - container, - aux_key, - system, - p_variable_results, - ) - return -end - -function calculate_aux_variable_value!( - container::OptimizationContainer, - aux_key::AuxVarKey{EnergyOutput, T}, - system::PSY.System, -) where {T <: PSY.HydroPumpedStorage} - p_variable_results = get_variable(container, ActivePowerOutVariable(), T) - _calculate_aux_variable_value!( - container, - aux_key, - system, - p_variable_results, - ) - return -end - ##################################### Hydro generation cost ############################ function objective_function!( container::OptimizationContainer, From 2c031c6eed50e52c651971f42ba799893e1f72d0 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 3 May 2023 09:32:45 -0600 Subject: [PATCH 144/370] add test and check --- src/utils/powersystems_utils.jl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/utils/powersystems_utils.jl b/src/utils/powersystems_utils.jl index 3e8d29a1a1..2af80e6319 100644 --- a/src/utils/powersystems_utils.jl +++ b/src/utils/powersystems_utils.jl @@ -11,7 +11,6 @@ function get_available_components( sys::PSY.System, f::Function, ) where {T <: PSY.Component} -<<<<<<< HEAD return PSY.get_components(x -> PSY.get_available(x) && f(x), T, sys) end @@ -25,9 +24,6 @@ function get_available_components( PSY.Bus, sys, ) -======= - return f(PSY.get_components(PSY.get_available, T, sys)) ->>>>>>> 55415f84d (add option to pass a second filter function) end function get_available_components( From 3a5477387cbe9bca3de77d78f90e3c7e864e5769 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 4 May 2023 10:28:17 -0600 Subject: [PATCH 145/370] add fix --- .../devices/hydro_generation.jl | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index a6f2871ef1..53a5623a31 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -721,6 +721,36 @@ function _calculate_aux_variable_value!( return end +function calculate_aux_variable_value!( + container::OptimizationContainer, + ::AuxVarKey{EnergyOutput, T}, + system::PSY.System, +) where {T <: PSY.HydroGen} + p_variable_results = get_variable(container, ActivePowerVariable(), T) + _calculate_aux_variable_value!( + container, + ::AuxVarKey{EnergyOutput, T}, + system, + p_variable_results, + ) + return +end + +function calculate_aux_variable_value!( + container::OptimizationContainer, + ::AuxVarKey{EnergyOutput, T}, + system::PSY.System, +) where {T <: PSY.HydroPumpedStorage} + p_variable_results = get_variable(container, ActivePowerOutVariable(), T) + _calculate_aux_variable_value!( + container, + ::AuxVarKey{EnergyOutput, T}, + system, + p_variable_results, + ) + return +end + ##################################### Hydro generation cost ############################ function objective_function!( container::OptimizationContainer, From 1c94ae11b83ab5baca0330b9f52458b29b94106d Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 4 May 2023 11:03:39 -0600 Subject: [PATCH 146/370] fix error --- src/devices_models/devices/hydro_generation.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 53a5623a31..4b57354321 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -723,13 +723,13 @@ end function calculate_aux_variable_value!( container::OptimizationContainer, - ::AuxVarKey{EnergyOutput, T}, + aux_key::AuxVarKey{EnergyOutput, T}, system::PSY.System, ) where {T <: PSY.HydroGen} p_variable_results = get_variable(container, ActivePowerVariable(), T) _calculate_aux_variable_value!( container, - ::AuxVarKey{EnergyOutput, T}, + aux_key, system, p_variable_results, ) @@ -738,13 +738,13 @@ end function calculate_aux_variable_value!( container::OptimizationContainer, - ::AuxVarKey{EnergyOutput, T}, + aux_key::AuxVarKey{EnergyOutput, T}, system::PSY.System, ) where {T <: PSY.HydroPumpedStorage} p_variable_results = get_variable(container, ActivePowerOutVariable(), T) _calculate_aux_variable_value!( container, - ::AuxVarKey{EnergyOutput, T}, + aux_key, system, p_variable_results, ) From d015286c65d0f90c47caddfc72212f4663703eb1 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 4 May 2023 11:25:43 -0600 Subject: [PATCH 147/370] remove variable overwrite --- src/devices_models/devices/hydro_generation.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 4b57354321..65792bb3bf 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -707,7 +707,6 @@ function _calculate_aux_variable_value!( system::PSY.System, p_variable_results::JuMPVariableArray, ) where {T <: PSY.HydroGen} - p_variable_results = get_variable(container, ActivePowerVariable(), T) devices = axes(p_variable_results, 1) time_steps = get_time_steps(container) resolution = get_resolution(container) From 4d85839187abcbd72a62688949a69925a00cc44c Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 12 May 2023 12:31:28 -0600 Subject: [PATCH 148/370] Bump version to v0.20.2 --- Project.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Project.toml b/Project.toml index ba7107aaa8..4374347e1c 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,11 @@ name = "PowerSimulations" uuid = "e690365d-45e2-57bb-ac84-44ba829e73c4" authors = ["Jose Daniel Lara", "Clayton Barrows", "Daniel Thom", "Dheepak Krishnamurthy", "Sourabh Dalvi"] +<<<<<<< HEAD version = "0.20.3" +======= +version = "0.20.2" +>>>>>>> bebcf0d56 (Bump version to v0.20.2) [deps] CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" From 9f3d6ebc9078bd81afd0a9b3a1bbefa82c1970c3 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 9 May 2023 11:57:38 -0600 Subject: [PATCH 149/370] remove code --- docs/make.jl | 1 - docs/src/formulation_library/General.md | 2 +- docs/src/formulation_library/HydroGen.md | 494 ------ src/PowerSimulations.jl | 8 - src/core/formulations.jl | 33 - .../hydrogeneration_constructor.jl | 1482 ----------------- .../devices/hydro_generation.jl | 822 --------- ...st_device_hydro_generation_constructors.jl | 642 ------- test/test_services_constructor.jl | 23 - 9 files changed, 1 insertion(+), 3506 deletions(-) delete mode 100644 docs/src/formulation_library/HydroGen.md delete mode 100644 src/devices_models/device_constructors/hydrogeneration_constructor.jl delete mode 100644 src/devices_models/devices/hydro_generation.jl delete mode 100644 test/test_device_hydro_generation_constructors.jl diff --git a/docs/make.jl b/docs/make.jl index 997ea23e72..0a306e5e30 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -34,7 +34,6 @@ pages = OrderedDict( "Formulation Library" => Any[ "General" => "formulation_library/General.md", "Thermal Generation" => "formulation_library/ThermalGen.md", - "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", diff --git a/docs/src/formulation_library/General.md b/docs/src/formulation_library/General.md index 75ee8c70c2..0330f848f3 100644 --- a/docs/src/formulation_library/General.md +++ b/docs/src/formulation_library/General.md @@ -29,7 +29,7 @@ using PowerSystems using DataFrames using Latexify combo_tables = [] -for t in [RenewableGen, ThermalGen, HydroGen, ElectricLoad] +for t in [RenewableGen, ThermalGen, ElectricLoad] combos = PowerSimulations.get_default_time_series_names(t, FixedOutput) combo_table = DataFrame( "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md deleted file mode 100644 index 1d587cf70d..0000000000 --- a/docs/src/formulation_library/HydroGen.md +++ /dev/null @@ -1,494 +0,0 @@ -# `PowerSystems.HydroGen` Formulations - -Valid `DeviceModel`s for subtypes of `HydroGen` include the following: - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.generate_device_formulation_combinations() -filter!(x -> x["device_type"] <: HydroGen, combos) -combo_table = DataFrame( - "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], - "Device Type" => ["[$(c["device_type"])](https://nrel-Sienna.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], - "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], - ) -mdtable(combo_table, latex = false) -``` - ---- - -## `HydroDispatchRunOfRiver` - -```@docs -HydroDispatchRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroDispatchRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref network_formulations) - -**Constraints:** - -```math -\begin{aligned} -& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} -\end{aligned} -``` - ---- - -## `HydroDispatchPumpedStorage` - -```@docs -HydroDispatchPumpedStorage -``` - -**Variables:** - -- [`ActivePowerInVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `-1 * PowerSystems.get_active_power(device)` -- [`ActivePowerOutVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`EnergyVariableUp`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device).up` -- [`EnergyVariableDown`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device).down` -- [`WaterSpillageVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`EnergyOutput`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`ReservationVariable`](@ref): - - only included if `DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage; attributes = Dict(reservation => true))` - - Bounds: {0, 1} - - Default initial value: 1 - -**Static Parameters:** - -- ``Pg^\text{out, max}`` = `map(x -> x.max - x.min, PowerSystems.get_active_power_limits(device))` -- ``Pg^\text{in, max}`` = `map(x -> x.max - x.min, PowerSystems.get_active_power_limits_pump(device))` -- ``Eg^\text{up, max}`` = `PowerSystems.get_storage_capacity(device).up` -- ``Eg^\text{down, max}`` = `PowerSystems.get_storage_capacity(device).down` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroPumpedStorage, HydroDispatchPumpedStorage) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg^{out}``. - -**Expressions:** - -Adds ``Pg`` term(s) to the active power balance expression(s) created by the selected [Network Formulations](@ref network_formulations) - -**Constraints:** - -```math -\begin{aligned} -& E^{up}_{t+1} = E^{up}_t + (InflowTimeSeriesParameter_t - S_t - Pg^{out}_t + Pg^{in}_t) \cdot \Delta T \\ -& E^{down}_{t+1} = E^{down}_t + (S_t - OutflowTimeSeriesParameter_t + Pg^{out}_t - Pg^{in}_t) \cdot \Delta T \\ -& Pg^{in}_t - r * Pg^\text{in, max} \le Pg^\text{in, max} \\ -& Pg^{out}_t + r * Pg^\text{out, max} \le Pg^\text{out, max} \\ -& E^{up}_t \le E^{up, max} -& E^{down}_t \le E^{down, max} -\end{aligned} -``` - ---- - -## `HydroDispatchReservoirBudget` - -```@docs -HydroDispatchReservoirBudget -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - TODO - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroDispatchReservoirBudget) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref network_formulations) - -**Constraints:** - -```math -\begin{aligned} -& Pg^\text{min} \le Pg_t \le Pg^\text{max} \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} \\ -& \sum_{t = 1}^N(Pg_t) \cdot \Delta T \le \sum_{t = 1}^N(EnergyBudgetTimeSeriesParameter_t) \cdot \Delta T -\end{aligned} -``` - ---- - -## `HydroDispatchReservoirStorage` - -```@docs -HydroDispatchReservoirStorage -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`EnergyVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device)` -- [`WaterSpillageVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`EnergyShortageVariable`](@ref): - - Bounds: [ , 0.0] - - Default initial value: 0.0 -- [`EnergySurplusVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` -- ``Eg^\text{max}`` = `PowerSystems.get_storage_capacity(device)` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroDispatchReservoirStorage) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. -TODO: add slack terms - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref network_formulations) - -**Constraints:** - -```math -\begin{aligned} -& E_{t+1} = E_t + (InflowTimeSeriesParameter_t - S_t - Pg_t) \cdot \Delta T \\ -& E_t - E^{surplus}_t + E^{shortage}_t = EnergyTargetTimeSeriesParameter_t \\ -& Pg^\text{min} \le Pg_t \le Pg^\text{max} \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} -\end{aligned} -``` - ---- - -## `HydroCommitmentReservoirBudget` - -```@docs -HydroCommitmentReservoirBudget -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - TODO - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroCommitmentReservoirBudget) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref network_formulations) - -**Constraints:** - -```math -\begin{aligned} -& \sum_{t = 1}^N P_t \cdot \Delta T \le E^\text{budget} \\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` - ---- - -## `HydroCommitmentReservoirStorage` - -```@docs -HydroCommitmentReservoirStorage -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`EnergyVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_initial_storage(device)` -- [`WaterSpillageVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`EnergyShortageVariable`](@ref): - - Bounds: [ , 0.0] - - Default initial value: 0.0 -- [`EnergySurplusVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: 0.0 -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Auxillary Variables:** - -- [`EnergyOutput`](@ref) - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Pg^\text{max}`` = `PowerSystems.get_active_power_limits(device).max` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` -- ``Eg^\text{max}`` = `PowerSystems.get_storage_capacity(device)` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroEnergyReservoir, HydroCommitmentReservoirStorage) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``, -and objective function terms for [StorageManagementCost](@ref). - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref network_formulations) - -**Constraints:** - -```math -\begin{aligned} -& E_{t+1} = E_t + (InflowTimeSeriesParameter_t - S_t - Pg_t) \cdot \Delta T \\ -& E_t - E^{surplus}_t + E^{shortage}_t = EnergyTargetTimeSeriesParameter_t \\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` - ---- - -## `HydroCommitmentRunOfRiver` - -```@docs -HydroCommitmentRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroCommitmentRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref network_formulations) - -**Constraints:** - -```math -\begin{aligned} -& Pg_t \le Pg^\text{max}\\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index b1e31398f6..7b0705a91e 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -51,14 +51,6 @@ export PowerLoadDispatch ######## Renewable Formulations ######## export RenewableFullDispatch export RenewableConstantPowerFactor -######## Hydro Formulations ######## -export HydroDispatchRunOfRiver -export HydroDispatchReservoirBudget -export HydroDispatchReservoirStorage -export HydroCommitmentRunOfRiver -export HydroCommitmentReservoirBudget -export HydroCommitmentReservoirStorage -export HydroDispatchPumpedStorage ######## Thermal Formulations ######## export ThermalStandardUnitCommitment diff --git a/src/core/formulations.jl b/src/core/formulations.jl index dedffc553a..948289a0e0 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -74,45 +74,12 @@ struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end ############################ Hydro Generation Formulations ################################# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end -abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end -abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end -abstract type AbstractHydroReservoirFormulation <: AbstractHydroDispatchFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end -""" -Formulation type to add injection variables constrained by total energy production budget defined with a time series for `HydroGen` -""" -struct HydroDispatchReservoirBudget <: AbstractHydroReservoirFormulation end - -""" -Formulation type to constrain hydropower production with a representation of the energy storage capacity and water inflow time series of a reservoir for `HydroGen` -""" -struct HydroDispatchReservoirStorage <: AbstractHydroReservoirFormulation end - -""" -Formulation type to constrain energy production from pumped storage with a representation of the energy storage capacity of upper and lower reservoirs and water inflow time series of upper reservoir and outflow time series of lower reservoir for `HydroPumpedStorage` -""" -struct HydroDispatchPumpedStorage <: AbstractHydroReservoirFormulation end - -""" -Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` -""" -struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end - -""" -Formulation type to add commitment and injection variables constrained by total energy production budget defined with a time series for `HydroGen` -""" -struct HydroCommitmentReservoirBudget <: AbstractHydroUnitCommitment end - -""" -Formulation type to constrain hydropower production with unit commitment variables and a representation of the energy storage capacity and water inflow time series of a reservoir for `HydroGen` -""" -struct HydroCommitmentReservoirStorage <: AbstractHydroUnitCommitment end - ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end struct ReserveLimitedRegulation <: AbstractRegulationFormulation end diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl deleted file mode 100644 index a2483f8e70..0000000000 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ /dev/null @@ -1,1482 +0,0 @@ -""" -Construct model for HydroGen with FixedOutput Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -function construct_device!( - ::OptimizationContainer, - ::PSY.System, - ::ModelConstructStage, - ::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - # FixedOutput doesn't add any constraints to the model. This function covers - # AbstractPowerModel and AbtractActivePowerModel - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -""" -Construct model for HydroGen with RunOfRiver Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with RunOfRiver Dispatch Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirBudget Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirBudget()) - add_variables!( - container, - ReactivePowerVariable, - devices, - HydroDispatchReservoirBudget(), - ) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirBudget()) - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirBudget Dispatch Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirBudget()) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirBudget()) - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirBudget}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with ReservoirStorage Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirStorage()) - add_variables!( - container, - ReactivePowerVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!(container, EnergyVariable, devices, HydroDispatchReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirStorage()) - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroDispatchReservoirStorage(), - InitialEnergyLevel(), - ) - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirStorage Dispatch Formulation -with only Active Power -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, HydroDispatchReservoirStorage()) - add_variables!(container, EnergyVariable, devices, HydroDispatchReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroDispatchReservoirStorage(), - ) - add_variables!(container, EnergyOutput, devices, HydroDispatchReservoirStorage()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroDispatchReservoirStorage(), - InitialEnergyLevel(), - ) - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirBudget Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentReservoirBudget, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentReservoirBudget, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with ReservoirBudget Commitment Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentReservoirBudget, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyBudgetTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentReservoirBudget, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - # Energy Budget Constraint - add_constraints!(container, EnergyBudgetConstraint, devices, model, network_model) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with ReservoirStorage Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!( - container, - ActivePowerVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - ReactivePowerVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!(container, OnVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!(container, EnergyVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!(container, EnergyOutput, devices, HydroCommitmentReservoirStorage()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroCommitmentReservoirStorage(), - InitialEnergyLevel(), - ) - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with ReservoirStorage Dispatch Formulation -with only Active Power -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!( - container, - ActivePowerVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!(container, OnVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!(container, EnergyVariable, devices, HydroCommitmentReservoirStorage()) - add_variables!( - container, - WaterSpillageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergyShortageVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - add_variables!( - container, - EnergySurplusVariable, - devices, - HydroCommitmentReservoirStorage(), - ) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_variables!(container, EnergyOutput, devices, HydroCommitmentReservoirStorage()) - add_parameters!(container, EnergyTargetTimeSeriesParameter, devices, model) - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroCommitmentReservoirStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroEnergyReservoir, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroCommitmentReservoirStorage(), - InitialEnergyLevel(), - ) - - # Energy Balance Constraint - add_constraints!(container, EnergyBalanceConstraint, devices, model, network_model) - add_constraints!(container, EnergyTargetConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroPumpedStorage with PumpedStorage Dispatch Formulation -with only Active Power -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, HydroDispatchPumpedStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroPumpedStorage, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerInVariable, devices, HydroDispatchPumpedStorage()) - add_variables!(container, ActivePowerOutVariable, devices, HydroDispatchPumpedStorage()) - add_variables!(container, EnergyVariableUp, devices, HydroDispatchPumpedStorage()) - add_variables!(container, EnergyVariableDown, devices, HydroDispatchPumpedStorage()) - add_variables!(container, WaterSpillageVariable, devices, HydroDispatchPumpedStorage()) - add_variables!(container, EnergyOutput, devices, HydroDispatchPumpedStorage()) - if get_attribute(model, "reservation") - add_variables!( - container, - ReservationVariable, - devices, - HydroDispatchPumpedStorage(), - ) - end - - add_parameters!(container, InflowTimeSeriesParameter, devices, model) - add_parameters!(container, OutflowTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerInVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ReserveRangeExpressionLB, devices, model) - add_expressions!(container, ReserveRangeExpressionUB, devices, model) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, HydroDispatchPumpedStorage}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroPumpedStorage, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - OutputActivePowerVariableLimitsConstraint, - ActivePowerOutVariable, - devices, - model, - network_model, - ) - add_constraints!( - container, - InputActivePowerVariableLimitsConstraint, - ActivePowerInVariable, - devices, - model, - network_model, - ) - - add_initial_condition!( - container, - devices, - HydroDispatchPumpedStorage(), - InitialEnergyLevelUp(), - ) - add_initial_condition!( - container, - devices, - HydroDispatchPumpedStorage(), - InitialEnergyLevelDown(), - ) - - # Energy Balanace limits - add_constraints!(container, EnergyCapacityUpConstraint, devices, model, network_model) - add_constraints!(container, EnergyCapacityDownConstraint, devices, model, network_model) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl deleted file mode 100644 index 65792bb3bf..0000000000 --- a/src/devices_models/devices/hydro_generation.jl +++ /dev/null @@ -1,822 +0,0 @@ -#! format: off -requires_initialization(::AbstractHydroFormulation) = false -requires_initialization(::AbstractHydroUnitCommitment) = true - -get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroPumpedStorage}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ReserveRangeExpressionUB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroPumpedStorage}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ReserveRangeExpressionLB - -########################### ActivePowerVariable, HydroGen ################################# -get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 -get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max - -############## ActivePowerVariable, HydroDispatchRunOfRiver #################### -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 - -############## ReactivePowerVariable, HydroGen #################### -get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min -get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max - -############## EnergyVariable, HydroGen #################### -get_variable_binary(::EnergyVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(pv::EnergyVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d) -get_variable_lower_bound(::EnergyVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) - -########################### EnergyVariableUp, HydroGen ################################# -get_variable_binary(::EnergyVariableUp, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(pv::EnergyVariableUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).up -get_variable_lower_bound(::EnergyVariableUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyVariableUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d).up - -########################### EnergyVariableDown, HydroGen ################################# -get_variable_binary(::EnergyVariableDown, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::EnergyVariableDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).down -get_variable_lower_bound(::EnergyVariableDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyVariableDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d).down - -########################### ActivePowerInVariable, HydroGen ################################# -get_variable_binary(::ActivePowerInVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::ActivePowerInVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::ActivePowerInVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = nothing -get_variable_multiplier(::ActivePowerInVariable, d::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = -1.0 - -########################### ActivePowerOutVariable, HydroGen ################################# -get_variable_binary(::ActivePowerOutVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::ActivePowerOutVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::ActivePowerOutVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = nothing -get_variable_multiplier(::ActivePowerOutVariable, d::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 - -############## OnVariable, HydroGen #################### -get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true -get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 - -############## WaterSpillageVariable, HydroGen #################### -get_variable_binary(::WaterSpillageVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::WaterSpillageVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 - -############## ReservationVariable, HydroGen #################### -get_variable_binary(::ReservationVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true -get_variable_binary(::ReservationVariable, ::Type{<:PSY.HydroPumpedStorage}, ::AbstractHydroFormulation) = true - -############## EnergyShortageVariable, HydroGen #################### -get_variable_binary(::EnergyShortageVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_lower_bound(::EnergyShortageVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_upper_bound(::EnergyShortageVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) -get_variable_upper_bound(::EnergyShortageVariable, d::PSY.HydroPumpedStorage, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d).up -############## EnergySurplusVariable, HydroGen #################### -get_variable_binary(::EnergySurplusVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_upper_bound(::EnergySurplusVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = 0.0 -get_variable_lower_bound(::EnergySurplusVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = - PSY.get_storage_capacity(d) -get_variable_lower_bound(::EnergySurplusVariable, d::PSY.HydroPumpedStorage, ::AbstractHydroFormulation) = - PSY.get_storage_capacity(d).up -########################### Parameter related set functions ################################ -get_multiplier_value(::EnergyBudgetTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::EnergyBudgetTimeSeriesParameter, d::PSY.HydroEnergyReservoir, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) -get_multiplier_value(::EnergyTargetTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_storage_capacity(d) -get_multiplier_value(::InflowTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_inflow(d) * PSY.get_conversion_factor(d) -get_multiplier_value(::OutflowTimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_outflow(d) * PSY.get_conversion_factor(d) -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) - -get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min - -#################### Initial Conditions for models ############### -initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) -initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() -initial_condition_default(::InitialEnergyLevel, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d) -initial_condition_variable(::InitialEnergyLevel, d::PSY.HydroGen, ::AbstractHydroFormulation) = EnergyVariable() -initial_condition_default(::InitialEnergyLevelUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).up -initial_condition_variable(::InitialEnergyLevelUp, d::PSY.HydroGen, ::AbstractHydroFormulation) = EnergyVariableUp() -initial_condition_default(::InitialEnergyLevelDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_initial_storage(d).down -initial_condition_variable(::InitialEnergyLevelDown, d::PSY.HydroGen, ::AbstractHydroFormulation) = EnergyVariableDown() -initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 -initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) -initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() - -########################Objective Function################################################## -proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 -proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_surplus_cost(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_shortage_cost(cost) - -objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::EnergySurplusVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_NEGATIVE -objective_function_multiplier(::EnergyShortageVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE - -sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE -sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE - -variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 -variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) -variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) - -#! format: on - -function get_initial_conditions_device_model( - ::OperationModel, - model::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroEnergyReservoir} - return model -end - -function get_initial_conditions_device_model( - ::OperationModel, - ::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroDispatch} - return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) -end - -function get_initial_conditions_device_model( - ::OperationModel, - ::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroPumpedStorage} - return DeviceModel(PSY.HydroPumpedStorage, HydroDispatchPumpedStorage) -end - -function get_default_time_series_names( - ::Type{<:PSY.HydroGen}, - ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - ActivePowerTimeSeriesParameter => "max_active_power", - ReactivePowerTimeSeriesParameter => "max_active_power", - ) -end - -function get_default_time_series_names( - ::Type{PSY.HydroEnergyReservoir}, - ::Type{<:Union{HydroCommitmentReservoirBudget, HydroDispatchReservoirBudget}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - EnergyBudgetTimeSeriesParameter => "hydro_budget", - ) -end - -function get_default_time_series_names( - ::Type{PSY.HydroEnergyReservoir}, - ::Type{<:Union{HydroDispatchReservoirStorage, HydroCommitmentReservoirStorage}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - EnergyTargetTimeSeriesParameter => "storage_target", - InflowTimeSeriesParameter => "inflow", - ) -end - -function get_default_time_series_names( - ::Type{PSY.HydroPumpedStorage}, - ::Type{<:HydroDispatchPumpedStorage}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - InflowTimeSeriesParameter => "inflow", - OutflowTimeSeriesParameter => "outflow", - ) -end - -function get_default_attributes( - ::Type{T}, - ::Type{D}, -) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} - return Dict{String, Any}("reservation" => false) -end - -function get_default_attributes( - ::Type{PSY.HydroPumpedStorage}, - ::Type{HydroDispatchPumpedStorage}, -) - return Dict{String, Any}("reservation" => true) -end - -""" -Time series constraints -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:RangeConstraintLBExpressions}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -""" -Add semicontinuous range constraints for Hydro Unit Commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -""" -Min and max reactive Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ReactivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_reactive_power_limits(x) -end - -""" -Min and max active Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_active_power_limits(x) -end - -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchRunOfRiver}, -) - return (min = 0.0, max = PSY.get_max_active_power(x)) -end - -""" -Add power variable limits constraints for hydro unit commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -""" -Add power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroGen, - W <: AbstractHydroDispatchFormulation, - X <: PM.AbstractPowerModel, -} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -""" -Add input power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{InputActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroReservoirFormulation, - X <: PM.AbstractPowerModel, -} - if get_attribute(model, "reservation") - add_reserve_range_constraints!(container, T, U, devices, model, X) - else - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - end - return -end - -""" -Add output power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroReservoirFormulation, - X <: PM.AbstractPowerModel, -} - if get_attribute(model, "reservation") - add_reserve_range_constraints!(container, T, U, devices, model, X) - else - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - end - return -end - -""" -Min and max output active power variable limits for hydro dispatch pumped storage -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:OutputActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchPumpedStorage}, -) - return PSY.get_active_power_limits(x) -end - -""" -Min and max input active power variable limits for hydro dispatch pumped storage -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:InputActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchPumpedStorage}, -) - return PSY.get_active_power_limits_pump(x) -end - -######################## Energy balance constraints ############################ - -""" -This function defines the constraints for the water level (or state of charge) -for the Hydro Reservoir. -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyBalanceConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroEnergyReservoir, - W <: AbstractHydroFormulation, - X <: PM.AbstractPowerModel, -} - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - names = [PSY.get_name(x) for x in devices] - initial_conditions = get_initial_condition(container, InitialEnergyLevel(), V) - energy_var = get_variable(container, EnergyVariable(), V) - power_var = get_variable(container, ActivePowerVariable(), V) - spillage_var = get_variable(container, WaterSpillageVariable(), V) - - constraint = add_constraints_container!( - container, - EnergyBalanceConstraint(), - V, - names, - time_steps, - ) - param_container = get_parameter(container, InflowTimeSeriesParameter(), V) - multiplier = get_parameter_multiplier_array(container, InflowTimeSeriesParameter(), V) - - for ic in initial_conditions - device = get_component(ic) - name = PSY.get_name(device) - param = get_parameter_column_values(param_container, name) - constraint[name, 1] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, 1] == - get_value(ic) - power_var[name, 1] * fraction_of_hour - - spillage_var[name, 1] * fraction_of_hour + param[1] * multiplier[name, 1] - ) - - for t in time_steps[2:end] - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, t] == - energy_var[name, t - 1] + param[t] * multiplier[name, t] - - power_var[name, t] * fraction_of_hour - - spillage_var[name, t] * fraction_of_hour - ) - end - end - return -end - -""" -This function defines the constraints for the water level (or state of charge) -for the HydroPumpedStorage. -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyCapacityUpConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroFormulation, - X <: PM.AbstractPowerModel, -} - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - names = [PSY.get_name(x) for x in devices] - initial_conditions = get_initial_condition(container, InitialEnergyLevelUp(), V) - - energy_var = get_variable(container, EnergyVariableUp(), V) - powerin_var = get_variable(container, ActivePowerInVariable(), V) - powerout_var = get_variable(container, ActivePowerOutVariable(), V) - spillage_var = get_variable(container, WaterSpillageVariable(), V) - - constraint = add_constraints_container!( - container, - EnergyCapacityUpConstraint(), - V, - names, - time_steps, - ) - param_container = get_parameter(container, InflowTimeSeriesParameter(), V) - multiplier = get_multiplier_array(param_container) - - for ic in initial_conditions - device = get_component(ic) - efficiency = PSY.get_pump_efficiency(device) - name = PSY.get_name(device) - constraint[name, 1] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, 1] == - get_value(ic) + - ( - powerin_var[name, 1] - - (spillage_var[name, 1] + powerout_var[name, 1]) / efficiency - ) * fraction_of_hour + - get_parameter_column_refs(param_container, name)[1] * multiplier[name, 1] - ) - - for t in time_steps[2:end] - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, t] == - energy_var[name, t - 1] + - get_parameter_column_refs(param_container, name)[t] * multiplier[name, t] + - ( - powerin_var[name, 1] - - (powerout_var[name, t] + spillage_var[name, t]) / efficiency - ) * fraction_of_hour - ) - end - end - return -end - -""" -Add energy capacity down constraints for hydro pumped storage -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyCapacityDownConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroPumpedStorage, - W <: AbstractHydroFormulation, - X <: PM.AbstractPowerModel, -} - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - names = [PSY.get_name(x) for x in devices] - initial_conditions = get_initial_condition(container, InitialEnergyLevelDown(), V) - - energy_var = get_variable(container, EnergyVariableDown(), V) - powerin_var = get_variable(container, ActivePowerInVariable(), V) - powerout_var = get_variable(container, ActivePowerOutVariable(), V) - spillage_var = get_variable(container, WaterSpillageVariable(), V) - - constraint = add_constraints_container!( - container, - EnergyCapacityDownConstraint(), - V, - names, - time_steps, - ) - - param_container = get_parameter(container, OutflowTimeSeriesParameter(), V) - multiplier = get_multiplier_array(param_container) - - for ic in initial_conditions - device = get_component(ic) - efficiency = PSY.get_pump_efficiency(device) - name = PSY.get_name(device) - param = get_parameter_column_refs(param_container, name) - constraint[name, 1] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, 1] == - get_value(ic) - - ( - spillage_var[name, 1] + powerout_var[name, 1] - - powerin_var[name, 1] / efficiency - ) * fraction_of_hour - param[1] * multiplier[name, 1] - ) - - for t in time_steps[2:end] - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - energy_var[name, t] == - energy_var[name, t - 1] - param[t] * multiplier[name, t] + - ( - powerout_var[name, t] - powerin_var[name, t] / efficiency + - spillage_var[name, t] - ) * fraction_of_hour - ) - end - end - return -end - -""" -Add energy target constraints for hydro gen -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyTargetConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroFormulation, X <: PM.AbstractPowerModel} - time_steps = get_time_steps(container) - set_name = [PSY.get_name(d) for d in devices] - constraint = add_constraints_container!( - container, - EnergyTargetConstraint(), - V, - set_name, - time_steps, - ) - - e_var = get_variable(container, EnergyVariable(), V) - shortage_var = get_variable(container, EnergyShortageVariable(), V) - surplus_var = get_variable(container, EnergySurplusVariable(), V) - param_container = get_parameter(container, EnergyTargetTimeSeriesParameter(), V) - multiplier = - get_parameter_multiplier_array(container, EnergyTargetTimeSeriesParameter(), V) - - for d in devices - name = PSY.get_name(d) - cost_data = PSY.get_operation_cost(d) - if isa(cost_data, PSY.StorageManagementCost) - shortage_cost = PSY.get_energy_shortage_cost(cost_data) - else - @debug "Data for device $name doesn't contain shortage costs" - shortage_cost = 0.0 - end - - if shortage_cost == 0.0 - @warn( - "Device $name has energy shortage cost set to 0.0, as a result the model will turnoff the EnergyShortageVariable to avoid infeasible/unbounded problem." - ) - JuMP.delete_upper_bound.(shortage_var[name, :]) - JuMP.set_upper_bound.(shortage_var[name, :], 0.0) - end - param = get_parameter_column_values(param_container, name) - for t in time_steps - constraint[name, t] = JuMP.@constraint( - container.JuMPmodel, - e_var[name, t] + shortage_var[name, t] + surplus_var[name, t] == - multiplier[name, t] * param[t] - ) - end - end - return -end - -##################################### Water/Energy Budget Constraint ############################ -""" -This function define the budget constraint for the -active power budget formulation. - -`` sum(P[t]) <= Budget `` -""" - -function add_constraints!( - container::OptimizationContainer, - ::Type{EnergyBudgetConstraint}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroFormulation, X <: PM.AbstractPowerModel} - time_steps = get_time_steps(container) - set_name = [PSY.get_name(d) for d in devices] - constraint = - add_constraints_container!(container, EnergyBudgetConstraint(), V, set_name) - - variable_out = get_variable(container, ActivePowerVariable(), V) - param_container = get_parameter(container, EnergyBudgetTimeSeriesParameter(), V) - multiplier = get_multiplier_array(param_container) - - for d in devices - name = PSY.get_name(d) - param = get_parameter_column_values(param_container, name) - constraint[name] = JuMP.@constraint( - container.JuMPmodel, - sum([variable_out[name, t] for t in time_steps]) <= - sum([multiplier[name, t] * param[t] for t in time_steps]) - ) - end - return -end - -##################################### Auxillary Variables ############################ -function _calculate_aux_variable_value!( - container::OptimizationContainer, - ::AuxVarKey{EnergyOutput, T}, - system::PSY.System, - p_variable_results::JuMPVariableArray, -) where {T <: PSY.HydroGen} - devices = axes(p_variable_results, 1) - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - aux_variable_container = get_aux_variable(container, EnergyOutput(), T) - for name in devices, t in time_steps - aux_variable_container[name, t] = - jump_value(p_variable_results[name, t]) * fraction_of_hour - end - - return -end - -function calculate_aux_variable_value!( - container::OptimizationContainer, - aux_key::AuxVarKey{EnergyOutput, T}, - system::PSY.System, -) where {T <: PSY.HydroGen} - p_variable_results = get_variable(container, ActivePowerVariable(), T) - _calculate_aux_variable_value!( - container, - aux_key, - system, - p_variable_results, - ) - return -end - -function calculate_aux_variable_value!( - container::OptimizationContainer, - aux_key::AuxVarKey{EnergyOutput, T}, - system::PSY.System, -) where {T <: PSY.HydroPumpedStorage} - p_variable_results = get_variable(container, ActivePowerOutVariable(), T) - _calculate_aux_variable_value!( - container, - aux_key, - system, - p_variable_results, - ) - return -end - -##################################### Hydro generation cost ############################ -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, OnVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{PSY.HydroPumpedStorage}, - ::DeviceModel{PSY.HydroPumpedStorage, T}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: HydroDispatchPumpedStorage} - add_variable_cost!(container, ActivePowerOutVariable(), devices, T()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where { - T <: PSY.HydroPumpedStorage, - U <: Union{HydroDispatchReservoirStorage, HydroDispatchReservoirBudget}, -} - add_variable_cost!(container, ActivePowerOutVariable(), devices, U()) - add_proportional_cost!(container, EnergySurplusVariable(), devices, U()) - add_proportional_cost!(container, EnergyShortageVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroEnergyReservoir, U <: HydroDispatchReservoirStorage} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, EnergySurplusVariable(), devices, U()) - add_proportional_cost!(container, EnergyShortageVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroEnergyReservoir, U <: HydroCommitmentReservoirStorage} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, EnergySurplusVariable(), devices, U()) - add_proportional_cost!(container, EnergyShortageVariable(), devices, U()) - return -end diff --git a/test/test_device_hydro_generation_constructors.jl b/test/test_device_hydro_generation_constructors.jl deleted file mode 100644 index ef37a71eab..0000000000 --- a/test/test_device_hydro_generation_constructors.jl +++ /dev/null @@ -1,642 +0,0 @@ -################################### -###### FIXED OUTPUT TESTS ######### -################################### - -@testset "Hydro DCPLossLess FixedOutput" begin - device_model = DeviceModel(HydroDispatch, FixedOutput) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with FixedOutput formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, FixedOutput) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -### RUN OF RIVER DISPATCH TESTS ### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -#### RUN OF RIVER COMMIT TESTS #### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -#### RESERVOIR BUDGET DISPATCH TESTS #### -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 25, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 49, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -#### PUMPED STORAGE DISPATCH TESTS #### -######################################### - -@testset "Hydro DCPLossLess HydroPumpedStorage with HydroDispatchPumpedStorage Formulations" begin - device_model = DeviceModel( - HydroPumpedStorage, - HydroDispatchPumpedStorage; - attributes = Dict{String, Any}("reservation" => false), - ) - c_sys5_phes_ed = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_phes_ed) - mock_construct_device!(model, device_model) - moi_tests(model, 60, 0, 24, 24, 24, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroPumpedStorage with HydroDispatchPumpedStorage with Reservation Formulations" begin - device_model = DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage) - c_sys5_phes_ed = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_phes_ed) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 24, 24, 24, true) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -### RESERVOIR BUDGET COMMITMENT TESTS ### -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 25, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentReservoirBudget Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirBudget) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 49, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -### RESERVOIR STORAGE DISPATCH TESTS #### -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 120, 0, 24, 24, 48, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPLossLess HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 144, 0, 48, 48, 48, false) - psi_checkobjfun_test(model, GAEVF) -end - -######################################### -### RESERVOIR STORAGE COMMITMENT TESTS ## -######################################### - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 144, 0, 24, 24, 48, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPLossLess HydroEnergyReservoir with HydroCommitmentReservoirStorage Formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 168, 0, 48, 48, 48, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Solving ED Hydro System using Dispatch Run of River" begin - sys = PSB.build_system(PSITestSystems, "c_sys5_hy") - networks = [ACPPowerModel, DCPPowerModel] - - test_results = Dict{Any, Float64}(ACPPowerModel => 177526.0, DCPPowerModel => 175521.0) - - for net in networks - @testset "HydroRoR ED model $(net)" begin - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroDispatch, HydroDispatchRunOfRiver) - ED = DecisionModel( - EconomicDispatchProblem, - template, - sys; - optimizer = ipopt_optimizer, - ) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == - PSI.BuildStatus.BUILT - psi_checksolve_test( - ED, - [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], - test_results[net], - 1000, - ) - end - end -end - -@testset "Solving ED Hydro System using Commitment Run of River" begin - sys = PSB.build_system(PSITestSystems, "c_sys5_hy") - net = DCPPowerModel - - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroDispatch, HydroCommitmentRunOfRiver) - - @testset "HydroRoR ED model $(net)" begin - ED = DecisionModel(UnitCommitmentProblem, template, sys; optimizer = GLPK_optimizer) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - psi_checksolve_test(ED, [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], 175521.0, 1000) - end -end - -@testset "Solving ED Hydro System using Dispatch with Reservoir" begin - systems = [ - PSB.build_system(PSITestSystems, "c_sys5_hyd"), - PSB.build_system(PSITestSystems, "c_sys5_hyd_ems"), - ] - networks = [ACPPowerModel, DCPPowerModel] - models = [HydroDispatchReservoirBudget, HydroDispatchReservoirStorage] - test_results = Dict{Any, Float64}( - (ACPPowerModel, HydroDispatchReservoirBudget) => 33423.0, - (DCPPowerModel, HydroDispatchReservoirBudget) => 33042.0, - (ACPPowerModel, HydroDispatchReservoirStorage) => 232497.0, - (DCPPowerModel, HydroDispatchReservoirStorage) => 230153.0, - ) - - for net in networks, (mod, sys) in zip(models, systems) - @testset "$(mod) ED model on $(net)" begin - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroEnergyReservoir, mod) - - ED = DecisionModel( - EconomicDispatchProblem, - template, - sys; - optimizer = ipopt_optimizer, - ) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == - PSI.BuildStatus.BUILT - psi_checksolve_test( - ED, - [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], - test_results[(net, mod)], - 10000, - ) - end - end -end - -@testset "Solving ED Hydro System using Commitment with Reservoir" begin - systems = [ - PSB.build_system(PSITestSystems, "c_sys5_hyd"), - PSB.build_system(PSITestSystems, "c_sys5_hyd_ems"), - ] - net = DCPPowerModel - models = [HydroCommitmentReservoirBudget, HydroCommitmentReservoirStorage] - test_results = Dict{Any, Float64}( - HydroCommitmentReservoirBudget => 33042.0, - HydroCommitmentReservoirStorage => 230153.0, - ) - - for (mod, sys) in zip(models, systems) - @testset "$(mod) ED model on $(net) and use_parameters = true" begin - template = get_thermal_dispatch_template_network(net) - set_device_model!(template, HydroEnergyReservoir, mod) - - ED = DecisionModel( - UnitCommitmentProblem, - template, - sys; - optimizer = GLPK_optimizer, - ) - @test build!(ED; output_dir = mktempdir(; cleanup = true)) == - PSI.BuildStatus.BUILT - psi_checksolve_test( - ED, - [MOI.OPTIMAL, MOI.LOCALLY_SOLVED], - test_results[mod], - 10000, - ) - end - end -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1b-2b)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_b_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], 5621.0, 10.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1c-2c)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_c_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], 21.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1d-2d)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_d_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], -5429.0, 10.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1e-2e)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_e_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], 21.0, 10.0) -end - -@testset "HydroEnergyReservoir with HydroDispatchReservoirStorage Formulations (energy target - cases 1f-2f)" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - set_device_model!(template, PowerLoad, StaticPowerLoad) - c_sys5_hyd = PSB.build_system(PSITestSystems, "hydro_test_case_f_sys") - - model = DecisionModel( - EconomicDispatchProblem, - template, - c_sys5_hyd; - optimizer = HiGHS_optimizer, - ) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 15, 0, 3, 3, 9, false) - psi_checksolve_test(model, [MOI.OPTIMAL], -17179.0) -end - -### Feedforward Test ### - -@testset "Test SemiContinuousFeedforward to HydroDispatch with HydroCommitmentRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - ff_sc = SemiContinuousFeedforward(; - component_type = HydroDispatch, - source = OnVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_sc) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 96, 0, 72, 48, 0, true) -end - -@testset "Test UpperBoundFeedforward to HydroDispatch with HydroCommitmentRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - ff_ub = UpperBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 96, 0, 72, 24, 0, true) -end - -@testset "Test LowerBoundFeedforward to HydroDispatch with HydroCommitmentRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - ff_ub = LowerBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 96, 0, 48, 48, 0, true) -end - -@testset "Test UpperBoundFeedforward to HydroDispatch with HydroDispatchRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - - ff_ub = UpperBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 72, 0, 72, 24, 0, false) -end - -@testset "Test LowerBoundFeedforward to HydroDispatch with HydroDispatchRunOfRiver model" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - - ff_ub = LowerBoundFeedforward(; - component_type = HydroDispatch, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_ub) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 72, 0, 48, 48, 0, false) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir with HydroDispatchReservoirBudget model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirBudget) - ff_il = EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 72, 0, 27, 24, 0, false) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir with HydroDispatchReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - ff_il = EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 193, 0, 26, 24, 48, false) -end - -@testset "Test LowerBoundFeedforward to HydroEnergyReservoir with HydroDispatchReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchReservoirStorage) - ff_il = LowerBoundFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 193, 0, 24, 48, 48, false) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir with HydroCommitmentReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - ff_il = EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ) - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 217, 0, 26, 24, 48, true) -end - -@testset "Test SemiContinuousFeedforward to HydroEnergyReservoir with HydroCommitmentReservoirStorage model" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentReservoirStorage) - ff_sc = SemiContinuousFeedforward(; - component_type = HydroEnergyReservoir, - source = OnVariable, - affected_values = [ActivePowerVariable], - ) - PSI.attach_feedforward!(device_model, ff_sc) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 217, 0, 48, 48, 48, true) -end - -@testset "Test EnergyLimitFeedforward to HydroEnergyReservoir models" begin - device_model = DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage) - - ff_il = EnergyLimitFeedforward(; - component_type = HydroPumpedStorage, - source = ActivePowerOutVariable, - affected_values = [ActivePowerOutVariable], - number_of_periods = 12, - ) - - PSI.attach_feedforward!(device_model, ff_il) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 110, 0, 25, 24, 24, true) -end - -@testset "Test EnergyTargetFeedforward to HydroEnergyReservoir models" begin - device_model = DeviceModel(HydroPumpedStorage, HydroDispatchPumpedStorage) - - ff_up = EnergyTargetFeedforward(; - component_type = HydroPumpedStorage, - source = EnergyVariableUp, - affected_values = [EnergyVariableUp], - target_period = 12, - penalty_cost = 1e4, - ) - - PSI.attach_feedforward!(device_model, ff_up) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_phes_ed") - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model; built_for_recurrent_solves = true) - moi_tests(model, 122, 0, 24, 25, 24, true) -end diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index 9c4100a19c..c264dd41ac 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -132,29 +132,6 @@ end moi_tests(model, 360, 0, 72, 120, 72, false) end -@testset "Test Reserves from Hydro" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, PowerLoad, StaticPowerLoad) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchRunOfRiver) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve5"), - ) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveDown}, RangeReserve, "Reserve6"), - ) - set_service_model!( - template, - ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), - ) - - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; add_reserves = true) - model = DecisionModel(template, c_sys5_hyd) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 240, 0, 48, 96, 72, false) -end - @testset "Test Reserves from with slack variables" begin template = get_thermal_dispatch_template_network( NetworkModel(CopperPlatePowerModel; use_slacks = true), From 484762e2ee6f3160a4add27054bf5ee9a8bffe0d Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 25 Apr 2023 13:59:51 -0600 Subject: [PATCH 150/370] move more code --- src/PowerSimulations.jl | 5 ++- src/core/formulations.jl | 2 +- test/test_simulation_build.jl | 84 ----------------------------------- 3 files changed, 4 insertions(+), 87 deletions(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 7b0705a91e..f2c45c3dd4 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -67,6 +67,9 @@ export ThermalCompactDispatch export DeviceLimitedRegulation export ReserveLimitedRegulation +###### Hydro ####### +export HydroDispatchRunOfRiver + # feedforward models export UpperBoundFeedforward export LowerBoundFeedforward @@ -525,7 +528,6 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") -include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") # Services Models @@ -547,7 +549,6 @@ include("initial_conditions/initialization.jl") # Device constructors include("devices_models/device_constructors/constructor_validations.jl") include("devices_models/device_constructors/thermalgeneration_constructor.jl") -include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 948289a0e0..4916aef959 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -78,7 +78,7 @@ abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ -struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end +struct HydroDispatchRunOfRiver <: AbstractHydroFormulation end ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end diff --git a/test/test_simulation_build.jl b/test/test_simulation_build.jl index 5acd725af5..b2fbe6589d 100644 --- a/test/test_simulation_build.jl +++ b/test/test_simulation_build.jl @@ -132,90 +132,6 @@ end @test_throws IS.ConflictingInputsError PSI._check_folder(sim) end -@testset "Multi-Stage Hydro Simulation Build" begin - sys_md = PSB.build_system(PSISystems, "5_bus_hydro_wk_sys") - - sys_uc = PSB.build_system(PSISystems, "5_bus_hydro_uc_sys") - transform_single_time_series!(sys_uc, 48, Hour(24)) - - sys_ed = PSB.build_system(PSISystems, "5_bus_hydro_ed_sys") - - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, ThermalStandard, ThermalBasicUnitCommitment) - set_device_model!(template, PowerLoad, StaticPowerLoad) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirBudget) - - template_uc = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template_uc, ThermalStandard, ThermalBasicUnitCommitment) - set_device_model!(template_uc, PowerLoad, StaticPowerLoad) - set_device_model!(template_uc, HydroEnergyReservoir, HydroDispatchRunOfRiver) - - template_ed = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template_ed, ThermalStandard, ThermalBasicUnitCommitment) - set_device_model!(template_ed, PowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchRunOfRiver) - - models = SimulationModels([ - DecisionModel( - template, - sys_md; - name = "MD", - initialize_model = false, - system_to_file = false, - optimizer = HiGHS_optimizer, - ), - DecisionModel( - template_uc, - sys_uc; - name = "UC", - initialize_model = false, - system_to_file = false, - optimizer = HiGHS_optimizer, - ), - DecisionModel( - template_ed, - sys_ed; - name = "ED", - initialize_model = false, - system_to_file = false, - optimizer = HiGHS_optimizer, - ), - ]) - - feedforwards = Dict( - "UC" => [ - EnergyLimitFeedforward(; - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - component_type = HydroEnergyReservoir, - number_of_periods = 24, - ), - ], - "ED" => [ - EnergyLimitFeedforward(; - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - component_type = HydroEnergyReservoir, - number_of_periods = 12, - ), - ], - ) - - test_sequence = SimulationSequence(; - models = models, - ini_cond_chronology = InterProblemChronology(), - feedforwards = feedforwards, - ) - - sim = Simulation(; - name = "test_md", - steps = 2, - models = models, - sequence = test_sequence, - simulation_folder = mktempdir(; cleanup = true), - ) - @test build!(sim; serialize = false) == PSI.BuildStatus.BUILT -end @testset "Test SemiContinuous Feedforward with Active and Reactive Power variables" begin template_uc = get_template_basic_uc_simulation() From 98aca437374ca8623e6e3d9cfc903961f62f6ef1 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:35 -0700 Subject: [PATCH 151/370] bring back hydro constructors --- src/PowerSimulations.jl | 3 + src/core/formulations.jl | 9 +- .../hydrogeneration_constructor.jl | 468 ++++++++++++++++++ .../devices/hydro_generation.jl | 297 +++++++++++ 4 files changed, 776 insertions(+), 1 deletion(-) create mode 100644 src/devices_models/device_constructors/hydrogeneration_constructor.jl create mode 100644 src/devices_models/devices/hydro_generation.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index f2c45c3dd4..41a1f0c63b 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -69,6 +69,7 @@ export ReserveLimitedRegulation ###### Hydro ####### export HydroDispatchRunOfRiver +export HydroCommitmentRunOfRiver # feedforward models export UpperBoundFeedforward @@ -528,6 +529,7 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") +include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") # Services Models @@ -549,6 +551,7 @@ include("initial_conditions/initialization.jl") # Device constructors include("devices_models/device_constructors/constructor_validations.jl") include("devices_models/device_constructors/thermalgeneration_constructor.jl") +include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 4916aef959..7522280c51 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -74,11 +74,18 @@ struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end ############################ Hydro Generation Formulations ################################# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end +abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end +abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ -struct HydroDispatchRunOfRiver <: AbstractHydroFormulation end +struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end + +""" +Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` +""" +struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl new file mode 100644 index 0000000000..75673eba77 --- /dev/null +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -0,0 +1,468 @@ +""" +Construct model for HydroGen with FixedOutput Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) + + # Expression + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + return +end + +function construct_device!( + ::OptimizationContainer, + ::PSY.System, + ::ModelConstructStage, + ::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} + # FixedOutput doesn't add any constraints to the model. This function covers + # AbstractPowerModel and AbstractActivePowerModel + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + # Expression + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + return +end + +""" +Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractPowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, ReactivePowerVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractPowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_constraints!( + container, + ReactivePowerVariableLimitsConstraint, + ReactivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + add_constraint_dual!(container, sys, model) + + return +end + +""" +Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation +with only Active Power. +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end + +""" +Construct model for HydroGen with RunOfRiver Commitment Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, ReactivePowerVariable, devices, D()) + add_variables!(container, OnVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_constraints!( + container, + ReactivePowerVariableLimitsConstraint, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end + +""" +Construct model for HydroGen with RunOfRiver Commitment Formulation +with only Active Power. +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: HydroCommitmentRunOfRiver, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, OnVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: HydroCommitmentRunOfRiver, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl new file mode 100644 index 0000000000..69e861b2c7 --- /dev/null +++ b/src/devices_models/devices/hydro_generation.jl @@ -0,0 +1,297 @@ +#! format: off +requires_initialization(::AbstractHydroFormulation) = false +requires_initialization(::AbstractHydroUnitCommitment) = true + +get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 +get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB +get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB + +########################### ActivePowerVariable, HydroGen ################################# +get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false +get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 +get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max + +############## ActivePowerVariable, HydroDispatchRunOfRiver #################### +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 + +############## ReactivePowerVariable, HydroGen #################### +get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false +get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power(d) +get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).min +get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).max + +############## OnVariable, HydroGen #################### +get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true +get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 + +########################### Parameter related set functions ################################ +get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) +get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) + +get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 +get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 +get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max +get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min + +#################### Initial Conditions for models ############### +initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) +initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() +initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) +initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() +initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 +initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() +initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) +initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() + +########################Objective Function################################################## +proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 +proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) +proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_surplus_cost(cost) +proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_shortage_cost(cost) + +objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::EnergySurplusVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_NEGATIVE +objective_function_multiplier(::EnergyShortageVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE + +sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE +sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE + +variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 +variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) +variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) + +#! format: on + +function get_initial_conditions_device_model( + ::OperationModel, + model::DeviceModel{T, <:AbstractHydroFormulation}, +) where {T <: PSY.HydroEnergyReservoir} + return model +end + +function get_initial_conditions_device_model( + ::OperationModel, + ::DeviceModel{T, <:AbstractHydroFormulation}, +) where {T <: PSY.HydroDispatch} + return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) +end + +function get_default_time_series_names( + ::Type{<:PSY.HydroGen}, + ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, +) + return Dict{Type{<:TimeSeriesParameter}, String}( + ActivePowerTimeSeriesParameter => "max_active_power", + ReactivePowerTimeSeriesParameter => "max_active_power", + ) +end + +function get_default_attributes( + ::Type{T}, + ::Type{D}, +) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} + return Dict{String, Any}("reservation" => false) +end + +""" +Time series constraints +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + add_parameterized_upper_bound_range_constraints( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + U, + ActivePowerTimeSeriesParameter, + devices, + model, + X, + ) + return +end + +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:RangeConstraintLBExpressions}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + return +end + +""" +Add semicontinuous range constraints for Hydro Unit Commitment formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + return +end + +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + add_parameterized_upper_bound_range_constraints( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + U, + ActivePowerTimeSeriesParameter, + devices, + model, + X, + ) + return +end + +""" +Min and max reactive Power Variable limits +""" +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ReactivePowerVariableLimitsConstraint}, + ::Type{<:AbstractHydroFormulation}, +) + return PSY.get_reactive_power_limits(x) +end + +""" +Min and max active Power Variable limits +""" +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ActivePowerVariableLimitsConstraint}, + ::Type{<:AbstractHydroFormulation}, +) + return PSY.get_active_power_limits(x) +end + +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ActivePowerVariableLimitsConstraint}, + ::Type{HydroDispatchRunOfRiver}, +) + return (min = 0.0, max = PSY.get_max_active_power(x)) +end + +""" +Add power variable limits constraints for hydro unit commitment formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{<:PowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + return +end + +""" +Add power variable limits constraints for hydro dispatch formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{<:PowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where { + V <: PSY.HydroGen, + W <: AbstractHydroDispatchFormulation, + X <: PM.AbstractPowerModel, +} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + return +end + +##################################### Auxillary Variables ############################ +function _calculate_aux_variable_value!( + container::OptimizationContainer, + ::AuxVarKey{EnergyOutput, T}, + system::PSY.System, + p_variable_results::JuMPVariableArray, +) where {T <: PSY.HydroGen} + devices = axes(p_variable_results, 1) + time_steps = get_time_steps(container) + resolution = get_resolution(container) + fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR + aux_variable_container = get_aux_variable(container, EnergyOutput(), T) + for name in devices, t in time_steps + aux_variable_container[name, t] = + jump_value(p_variable_results[name, t]) * fraction_of_hour + end + + return +end + +function calculate_aux_variable_value!( + container::OptimizationContainer, + aux_key::AuxVarKey{EnergyOutput, T}, + system::PSY.System, +) where {T <: PSY.HydroGen} + p_variable_results = get_variable(container, ActivePowerVariable(), T) + _calculate_aux_variable_value!( + container, + aux_key, + system, + p_variable_results, + ) + return +end + +##################################### Hydro generation cost ############################ +function objective_function!( + container::OptimizationContainer, + devices::IS.FlattenIteratorWrapper{T}, + ::DeviceModel{T, U}, + ::Type{<:PM.AbstractPowerModel}, +) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} + add_variable_cost!(container, ActivePowerVariable(), devices, U()) + add_proportional_cost!(container, OnVariable(), devices, U()) + return +end + +function objective_function!( + container::OptimizationContainer, + devices::IS.FlattenIteratorWrapper{T}, + ::DeviceModel{T, U}, + ::Type{<:PM.AbstractPowerModel}, +) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} + add_variable_cost!(container, ActivePowerVariable(), devices, U()) + return +end From 64ae6a1702b17dcf2702279f804075a23c80cbeb Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:42 -0700 Subject: [PATCH 152/370] bring back hydro tests --- ...st_device_hydro_generation_constructors.jl | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 test/test_device_hydro_generation_constructors.jl diff --git a/test/test_device_hydro_generation_constructors.jl b/test/test_device_hydro_generation_constructors.jl new file mode 100644 index 0000000000..7545c57ace --- /dev/null +++ b/test/test_device_hydro_generation_constructors.jl @@ -0,0 +1,121 @@ +################################### +###### FIXED OUTPUT TESTS ######### +################################### + +@testset "Hydro DCPLossLess FixedOutput" begin + device_model = DeviceModel(HydroDispatch, FixedOutput) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 0, 0, 0, 0, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with FixedOutput formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, FixedOutput) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 0, 0, 0, 0, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +################################### +### RUN OF RIVER DISPATCH TESTS ### +################################### + +@testset "Hydro DCPLossLess HydroDispatch with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 24, 0, 48, 24, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroDispatch with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 72, 48, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 24, 0, 48, 24, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 72, 48, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +################################### +#### RUN OF RIVER COMMIT TESTS #### +################################### + +@testset "Hydro DCPLossLess HydroDispatch with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 48, 24, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroDispatch with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 72, 0, 72, 48, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 48, 24, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 72, 0, 72, 48, 0, true) + psi_checkobjfun_test(model, GAEVF) +end From 1aa90b54b1184208c8f69ebebd933736f98ab6c3 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:57 -0700 Subject: [PATCH 153/370] remove reservoir budget from tests --- test/test_model_decision.jl | 62 ------------------ test/test_model_emulation.jl | 104 ------------------------------ test/test_print.jl | 7 -- test/test_services_constructor.jl | 23 +++++++ test/test_simulation_build.jl | 1 - test/test_simulation_execute.jl | 14 ---- test/test_simulation_results.jl | 11 +--- 7 files changed, 25 insertions(+), 197 deletions(-) diff --git a/test/test_model_decision.jl b/test/test_model_decision.jl index 12f3cb8074..3af76fc801 100644 --- a/test/test_model_decision.jl +++ b/test/test_model_decision.jl @@ -488,68 +488,6 @@ end HydroEnergyReservoir, ) @test solve!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroDispatchReservoirBudget ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; force_build = true) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirBudget) - model = DecisionModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test !PSI.has_initial_condition_value( - initial_conditions_data, - ActivePowerVariable(), - HydroEnergyReservoir, - ) - @test solve!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentReservoirBudget ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; force_build = true) - set_device_model!(template, HydroEnergyReservoir, HydroCommitmentReservoirBudget) - model = DecisionModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test PSI.has_initial_condition_value( - initial_conditions_data, - OnVariable(), - HydroEnergyReservoir, - ) - @test solve!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroDispatchReservoirStorage ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems"; force_build = true) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - model = DecisionModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test !PSI.has_initial_condition_value( - initial_conditions_data, - ActivePowerVariable(), - HydroEnergyReservoir, - ) - check_energy_initial_conditions_values(model, HydroEnergyReservoir) - @test solve!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentReservoirStorage ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd_ems"; force_build = true) - set_device_model!(template, HydroEnergyReservoir, HydroCommitmentReservoirStorage) - model = DecisionModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test PSI.has_initial_condition_value( - initial_conditions_data, - OnVariable(), - HydroEnergyReservoir, - ) - check_energy_initial_conditions_values(model, HydroEnergyReservoir) - @test solve!(model) == RunStatus.SUCCESSFUL end @testset "Test serialization of InitialConditionsData" begin diff --git a/test/test_model_emulation.jl b/test/test_model_emulation.jl index ba40caa9ba..06baefcf7f 100644 --- a/test/test_model_emulation.jl +++ b/test/test_model_emulation.jl @@ -142,110 +142,6 @@ end HydroEnergyReservoir, ) @test run!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentRunOfRiver ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system( - PSITestSystems, - "c_sys5_hyd"; - add_single_time_series = true, - force_build = true, - ) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirBudget) - model = EmulationModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; executions = 10, output_dir = mktempdir(; cleanup = true)) == - BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test !PSI.has_initial_condition_value( - initial_conditions_data, - ActivePowerVariable(), - HydroEnergyReservoir, - ) - @test run!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentRunOfRiver ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system( - PSITestSystems, - "c_sys5_hyd"; - add_single_time_series = true, - force_build = true, - ) - set_device_model!(template, HydroEnergyReservoir, HydroCommitmentReservoirBudget) - model = EmulationModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; executions = 10, output_dir = mktempdir(; cleanup = true)) == - BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test PSI.has_initial_condition_value( - initial_conditions_data, - OnVariable(), - HydroEnergyReservoir, - ) - @test run!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentRunOfRiver ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system( - PSITestSystems, - "c_sys5_hyd_ems"; - add_single_time_series = true, - force_build = true, - ) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchReservoirStorage) - model = EmulationModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; executions = 10, output_dir = mktempdir(; cleanup = true)) == - BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test !PSI.has_initial_condition_value( - initial_conditions_data, - ActivePowerVariable(), - HydroEnergyReservoir, - ) - ic_data = PSI.get_initial_condition( - PSI.get_optimization_container(model), - InitialEnergyLevel(), - HydroEnergyReservoir, - ) - for ic in ic_data - name = PSY.get_name(ic.component) - e_var = PSI.jump_value(PSI.get_value(ic)) - @test PSY.get_initial_storage(ic.component) == e_var - end - @test run!(model) == RunStatus.SUCCESSFUL - - ######## Test with HydroCommitmentRunOfRiver ######## - template = get_thermal_dispatch_template_network() - c_sys5_hyd = PSB.build_system( - PSITestSystems, - "c_sys5_hyd_ems"; - add_single_time_series = true, - force_build = true, - ) - set_device_model!(template, HydroEnergyReservoir, HydroCommitmentReservoirStorage) - model = EmulationModel(template, c_sys5_hyd; optimizer = HiGHS_optimizer) - @test build!(model; executions = 10, output_dir = mktempdir(; cleanup = true)) == - BuildStatus.BUILT - initial_conditions_data = - PSI.get_initial_conditions_data(PSI.get_optimization_container(model)) - @test PSI.has_initial_condition_value( - initial_conditions_data, - OnVariable(), - HydroEnergyReservoir, - ) - ic_data = PSI.get_initial_condition( - PSI.get_optimization_container(model), - InitialEnergyLevel(), - HydroEnergyReservoir, - ) - for ic in ic_data - name = PSY.get_name(ic.component) - e_var = PSI.jump_value(PSI.get_value(ic)) - @test PSY.get_initial_storage(ic.component) == e_var - end - @test run!(model) == RunStatus.SUCCESSFUL end @testset "Emulation Model Results" begin diff --git a/test/test_print.jl b/test/test_print.jl index 43c154d02a..ff1e6108ea 100644 --- a/test/test_print.jl +++ b/test/test_print.jl @@ -45,7 +45,6 @@ end template_uc = get_template_basic_uc_simulation() template_ed = get_template_nomin_ed_simulation() set_device_model!(template_ed, InterruptiblePowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchReservoirBudget) set_network_model!(template_uc, NetworkModel( CopperPlatePowerModel, # MILP "duals" not supported with free solvers @@ -88,12 +87,6 @@ end source = OnVariable, affected_values = [ActivePowerVariable], ), - EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ), ], ), ini_cond_chronology = InterProblemChronology(), diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index c264dd41ac..9c4100a19c 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -132,6 +132,29 @@ end moi_tests(model, 360, 0, 72, 120, 72, false) end +@testset "Test Reserves from Hydro" begin + template = ProblemTemplate(CopperPlatePowerModel) + set_device_model!(template, PowerLoad, StaticPowerLoad) + set_device_model!(template, HydroEnergyReservoir, HydroDispatchRunOfRiver) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve5"), + ) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveDown}, RangeReserve, "Reserve6"), + ) + set_service_model!( + template, + ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), + ) + + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; add_reserves = true) + model = DecisionModel(template, c_sys5_hyd) + @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT + moi_tests(model, 240, 0, 48, 96, 72, false) +end + @testset "Test Reserves from with slack variables" begin template = get_thermal_dispatch_template_network( NetworkModel(CopperPlatePowerModel; use_slacks = true), diff --git a/test/test_simulation_build.jl b/test/test_simulation_build.jl index b2fbe6589d..5bda0fa750 100644 --- a/test/test_simulation_build.jl +++ b/test/test_simulation_build.jl @@ -132,7 +132,6 @@ end @test_throws IS.ConflictingInputsError PSI._check_folder(sim) end - @testset "Test SemiContinuous Feedforward with Active and Reactive Power variables" begin template_uc = get_template_basic_uc_simulation() set_network_model!(template_uc, NetworkModel(DCPPowerModel; use_slacks = true)) diff --git a/test/test_simulation_execute.jl b/test/test_simulation_execute.jl index 783c4c5241..f50bab178f 100644 --- a/test/test_simulation_execute.jl +++ b/test/test_simulation_execute.jl @@ -38,7 +38,6 @@ function test_2_stage_decision_models_with_feedforwards(in_memory) template_uc = get_template_basic_uc_simulation() template_ed = get_template_nomin_ed_simulation() set_device_model!(template_ed, InterruptiblePowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchReservoirBudget) set_network_model!(template_uc, NetworkModel( CopperPlatePowerModel, # MILP "duals" not supported with free solvers @@ -80,12 +79,6 @@ function test_2_stage_decision_models_with_feedforwards(in_memory) source = OnVariable, affected_values = [ActivePowerVariable], ), - EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ), ], ), ini_cond_chronology = InterProblemChronology(), @@ -128,7 +121,6 @@ end ), ) set_device_model!(template_ed, InterruptiblePowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchReservoirBudget) c_sys5_hy_uc = PSB.build_system(PSITestSystems, "c_sys5_hy_uc") c_sys5_hy_ed = PSB.build_system(PSITestSystems, "c_sys5_hy_ed") models = SimulationModels(; @@ -157,12 +149,6 @@ end source = OnVariable, affected_values = [ActivePowerVariable], ), - EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ), ], ), ini_cond_chronology = InterProblemChronology(), diff --git a/test/test_simulation_results.jl b/test/test_simulation_results.jl index 98525c9302..4b8816d043 100644 --- a/test/test_simulation_results.jl +++ b/test/test_simulation_results.jl @@ -132,7 +132,6 @@ function test_simulation_results(file_path::String, export_path; in_memory = fal template_uc = get_template_basic_uc_simulation() template_ed = get_template_nomin_ed_simulation() set_device_model!(template_ed, InterruptiblePowerLoad, StaticPowerLoad) - set_device_model!(template_ed, HydroEnergyReservoir, HydroDispatchReservoirBudget) set_network_model!( template_uc, NetworkModel(CopperPlatePowerModel; duals = [CopperPlateBalanceConstraint]), @@ -173,12 +172,6 @@ function test_simulation_results(file_path::String, export_path; in_memory = fal source = OnVariable, affected_values = [ActivePowerVariable], ), - EnergyLimitFeedforward(; - component_type = HydroEnergyReservoir, - source = ActivePowerVariable, - affected_values = [ActivePowerVariable], - number_of_periods = 12, - ), ], ), ini_cond_chronology = InterProblemChronology(), @@ -230,7 +223,7 @@ function test_simulation_results(file_path::String, export_path; in_memory = fal verify_export_results(results, export_path) - @test length(readdir(export_realized_results(results_ed))) === 18 + @test length(readdir(export_realized_results(results_ed))) === 17 # Test that you can't read a failed simulation. PSI.set_simulation_status!(sim, RunStatus.FAILED) @@ -547,7 +540,7 @@ function test_emulation_problem_results(results::SimulationResults, in_memory) ) == 10 parameters_keys = collect(keys(read_realized_parameters(results_em))) - @test length(parameters_keys) == 7 + @test length(parameters_keys) == 5 parameters_inputs = ( [ "ActivePowerTimeSeriesParameter__PowerLoad", From ede6ed52c820592aa685e5b749cbf35d31d27a07 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 13:04:52 -0700 Subject: [PATCH 154/370] bring back hydro docs --- docs/make.jl | 1 + docs/src/formulation_library/General.md | 2 +- docs/src/formulation_library/HydroGen.md | 134 +++++++++++++++++++++++ 3 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 docs/src/formulation_library/HydroGen.md diff --git a/docs/make.jl b/docs/make.jl index 0a306e5e30..997ea23e72 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -34,6 +34,7 @@ pages = OrderedDict( "Formulation Library" => Any[ "General" => "formulation_library/General.md", "Thermal Generation" => "formulation_library/ThermalGen.md", + "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", diff --git a/docs/src/formulation_library/General.md b/docs/src/formulation_library/General.md index 0330f848f3..75ee8c70c2 100644 --- a/docs/src/formulation_library/General.md +++ b/docs/src/formulation_library/General.md @@ -29,7 +29,7 @@ using PowerSystems using DataFrames using Latexify combo_tables = [] -for t in [RenewableGen, ThermalGen, ElectricLoad] +for t in [RenewableGen, ThermalGen, HydroGen, ElectricLoad] combos = PowerSimulations.get_default_time_series_names(t, FixedOutput) combo_table = DataFrame( "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md new file mode 100644 index 0000000000..efe13982b3 --- /dev/null +++ b/docs/src/formulation_library/HydroGen.md @@ -0,0 +1,134 @@ +# `PowerSystems.HydroGen` Formulations + +Valid `DeviceModel`s for subtypes of `HydroGen` include the following: + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.generate_device_formulation_combinations() +filter!(x -> x["device_type"] <: HydroGen, combos) +combo_table = DataFrame( + "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], + "Device Type" => ["[$(c["device_type"])](https://nrel-siip.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], + "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], + ) +mdtable(combo_table, latex = false) +``` + +--- + +## `HydroDispatchRunOfRiver` + +```@docs +HydroDispatchRunOfRiver +``` + +**Variables:** + +- [`ActivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_active_power(device)` +- [`ReactivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_reactive_power(device)` + +**Static Parameters:** + +- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` +- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` +- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` + +**Time Series Parameters:** + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroDispatchRunOfRiver) +combo_table = DataFrame( + "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), + "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), + ) +mdtable(combo_table, latex = false) +``` + +**Objective:** + +Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg``. + +**Expressions:** + +Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) + +**Constraints:** + +```math +\begin{aligned} +& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ +& Qg^\text{min} \le Qg_t \le Qg^\text{max} +\end{aligned} +``` + +--- + +## `HydroCommitmentRunOfRiver` + +```@docs +HydroCommitmentRunOfRiver +``` + +**Variables:** + +- [`ActivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_active_power(device)` +- [`ReactivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_reactive_power(device)` +- [`OnVariable`](@ref): + - Bounds: {0, 1} + - Default initial value: `PowerSystems.get_status(device)` + +**Static Parameters:** + +- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` +- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` +- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` + +**Time Series Parameters:** + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroCommitmentRunOfRiver) +combo_table = DataFrame( + "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), + "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), + ) +mdtable(combo_table, latex = false) +``` + +**Objective:** + +Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. + +**Expressions:** + +Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) + +**Constraints:** + +```math +\begin{aligned} +& Pg_t \le Pg^\text{max}\\ +& Pg_t - u_t Pg^\text{max} \le 0 \\ +& Pg_t - u_t Pg^\text{min} \ge 0 \\ +& Qg_t - u_t Qg^\text{max} \le 0 \\ +& Qg_t - u_t Qg^\text{min} \ge 0 +\end{aligned} +``` \ No newline at end of file From 516e5c58f2c58fe4c2505dea70dc7f211dc8f495 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 7 Jul 2023 12:47:04 -0600 Subject: [PATCH 155/370] remove code --- docs/make.jl | 1 - docs/src/formulation_library/General.md | 2 +- docs/src/formulation_library/HydroGen.md | 134 ----- src/core/formulations.jl | 7 - .../hydrogeneration_constructor.jl | 468 ------------------ .../devices/hydro_generation.jl | 297 ----------- ...st_device_hydro_generation_constructors.jl | 121 ----- test/test_services_constructor.jl | 23 - 8 files changed, 1 insertion(+), 1052 deletions(-) delete mode 100644 docs/src/formulation_library/HydroGen.md delete mode 100644 src/devices_models/device_constructors/hydrogeneration_constructor.jl delete mode 100644 src/devices_models/devices/hydro_generation.jl delete mode 100644 test/test_device_hydro_generation_constructors.jl diff --git a/docs/make.jl b/docs/make.jl index 997ea23e72..0a306e5e30 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -34,7 +34,6 @@ pages = OrderedDict( "Formulation Library" => Any[ "General" => "formulation_library/General.md", "Thermal Generation" => "formulation_library/ThermalGen.md", - "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", diff --git a/docs/src/formulation_library/General.md b/docs/src/formulation_library/General.md index 75ee8c70c2..0330f848f3 100644 --- a/docs/src/formulation_library/General.md +++ b/docs/src/formulation_library/General.md @@ -29,7 +29,7 @@ using PowerSystems using DataFrames using Latexify combo_tables = [] -for t in [RenewableGen, ThermalGen, HydroGen, ElectricLoad] +for t in [RenewableGen, ThermalGen, ElectricLoad] combos = PowerSimulations.get_default_time_series_names(t, FixedOutput) combo_table = DataFrame( "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md deleted file mode 100644 index efe13982b3..0000000000 --- a/docs/src/formulation_library/HydroGen.md +++ /dev/null @@ -1,134 +0,0 @@ -# `PowerSystems.HydroGen` Formulations - -Valid `DeviceModel`s for subtypes of `HydroGen` include the following: - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.generate_device_formulation_combinations() -filter!(x -> x["device_type"] <: HydroGen, combos) -combo_table = DataFrame( - "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], - "Device Type" => ["[$(c["device_type"])](https://nrel-siip.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], - "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], - ) -mdtable(combo_table, latex = false) -``` - ---- - -## `HydroDispatchRunOfRiver` - -```@docs -HydroDispatchRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroDispatchRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} -\end{aligned} -``` - ---- - -## `HydroCommitmentRunOfRiver` - -```@docs -HydroCommitmentRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroCommitmentRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg_t \le Pg^\text{max}\\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` \ No newline at end of file diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 7522280c51..948289a0e0 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -74,19 +74,12 @@ struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end ############################ Hydro Generation Formulations ################################# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end -abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end -abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end -""" -Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` -""" -struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end - ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end struct ReserveLimitedRegulation <: AbstractRegulationFormulation end diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl deleted file mode 100644 index 75673eba77..0000000000 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ /dev/null @@ -1,468 +0,0 @@ -""" -Construct model for HydroGen with FixedOutput Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -function construct_device!( - ::OptimizationContainer, - ::PSY.System, - ::ModelConstructStage, - ::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - # FixedOutput doesn't add any constraints to the model. This function covers - # AbstractPowerModel and AbstractActivePowerModel - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -""" -Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl deleted file mode 100644 index 69e861b2c7..0000000000 --- a/src/devices_models/devices/hydro_generation.jl +++ /dev/null @@ -1,297 +0,0 @@ -#! format: off -requires_initialization(::AbstractHydroFormulation) = false -requires_initialization(::AbstractHydroUnitCommitment) = true - -get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB - -########################### ActivePowerVariable, HydroGen ################################# -get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 -get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max - -############## ActivePowerVariable, HydroDispatchRunOfRiver #################### -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 - -############## ReactivePowerVariable, HydroGen #################### -get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power(d) -get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).min -get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).max - -############## OnVariable, HydroGen #################### -get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true -get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 - -########################### Parameter related set functions ################################ -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) - -get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min - -#################### Initial Conditions for models ############### -initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) -initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() -initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 -initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) -initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() - -########################Objective Function################################################## -proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 -proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_surplus_cost(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_shortage_cost(cost) - -objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::EnergySurplusVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_NEGATIVE -objective_function_multiplier(::EnergyShortageVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE - -sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE -sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE - -variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 -variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) -variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) - -#! format: on - -function get_initial_conditions_device_model( - ::OperationModel, - model::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroEnergyReservoir} - return model -end - -function get_initial_conditions_device_model( - ::OperationModel, - ::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroDispatch} - return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) -end - -function get_default_time_series_names( - ::Type{<:PSY.HydroGen}, - ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - ActivePowerTimeSeriesParameter => "max_active_power", - ReactivePowerTimeSeriesParameter => "max_active_power", - ) -end - -function get_default_attributes( - ::Type{T}, - ::Type{D}, -) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} - return Dict{String, Any}("reservation" => false) -end - -""" -Time series constraints -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:RangeConstraintLBExpressions}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -""" -Add semicontinuous range constraints for Hydro Unit Commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -""" -Min and max reactive Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ReactivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_reactive_power_limits(x) -end - -""" -Min and max active Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_active_power_limits(x) -end - -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchRunOfRiver}, -) - return (min = 0.0, max = PSY.get_max_active_power(x)) -end - -""" -Add power variable limits constraints for hydro unit commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -""" -Add power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroGen, - W <: AbstractHydroDispatchFormulation, - X <: PM.AbstractPowerModel, -} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -##################################### Auxillary Variables ############################ -function _calculate_aux_variable_value!( - container::OptimizationContainer, - ::AuxVarKey{EnergyOutput, T}, - system::PSY.System, - p_variable_results::JuMPVariableArray, -) where {T <: PSY.HydroGen} - devices = axes(p_variable_results, 1) - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - aux_variable_container = get_aux_variable(container, EnergyOutput(), T) - for name in devices, t in time_steps - aux_variable_container[name, t] = - jump_value(p_variable_results[name, t]) * fraction_of_hour - end - - return -end - -function calculate_aux_variable_value!( - container::OptimizationContainer, - aux_key::AuxVarKey{EnergyOutput, T}, - system::PSY.System, -) where {T <: PSY.HydroGen} - p_variable_results = get_variable(container, ActivePowerVariable(), T) - _calculate_aux_variable_value!( - container, - aux_key, - system, - p_variable_results, - ) - return -end - -##################################### Hydro generation cost ############################ -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, OnVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - return -end diff --git a/test/test_device_hydro_generation_constructors.jl b/test/test_device_hydro_generation_constructors.jl deleted file mode 100644 index 7545c57ace..0000000000 --- a/test/test_device_hydro_generation_constructors.jl +++ /dev/null @@ -1,121 +0,0 @@ -################################### -###### FIXED OUTPUT TESTS ######### -################################### - -@testset "Hydro DCPLossLess FixedOutput" begin - device_model = DeviceModel(HydroDispatch, FixedOutput) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with FixedOutput formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, FixedOutput) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -### RUN OF RIVER DISPATCH TESTS ### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -#### RUN OF RIVER COMMIT TESTS #### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index 9c4100a19c..c264dd41ac 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -132,29 +132,6 @@ end moi_tests(model, 360, 0, 72, 120, 72, false) end -@testset "Test Reserves from Hydro" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, PowerLoad, StaticPowerLoad) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchRunOfRiver) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve5"), - ) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveDown}, RangeReserve, "Reserve6"), - ) - set_service_model!( - template, - ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), - ) - - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; add_reserves = true) - model = DecisionModel(template, c_sys5_hyd) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 240, 0, 48, 96, 72, false) -end - @testset "Test Reserves from with slack variables" begin template = get_thermal_dispatch_template_network( NetworkModel(CopperPlatePowerModel; use_slacks = true), From cea64cc5ea408bd8258e5378cd7936fb164b7598 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 25 Apr 2023 13:59:51 -0600 Subject: [PATCH 156/370] move more code --- src/PowerSimulations.jl | 3 --- src/core/formulations.jl | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 41a1f0c63b..f2c45c3dd4 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -69,7 +69,6 @@ export ReserveLimitedRegulation ###### Hydro ####### export HydroDispatchRunOfRiver -export HydroCommitmentRunOfRiver # feedforward models export UpperBoundFeedforward @@ -529,7 +528,6 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") -include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") # Services Models @@ -551,7 +549,6 @@ include("initial_conditions/initialization.jl") # Device constructors include("devices_models/device_constructors/constructor_validations.jl") include("devices_models/device_constructors/thermalgeneration_constructor.jl") -include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 948289a0e0..4916aef959 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -78,7 +78,7 @@ abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ -struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end +struct HydroDispatchRunOfRiver <: AbstractHydroFormulation end ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end From 820f5036709c9429cba2d5a59088f0fdb9f3c61c Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 24 Apr 2023 16:23:32 -0600 Subject: [PATCH 157/370] remove code --- test/test_services_constructor.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index c264dd41ac..f0ba76db4a 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -129,7 +129,7 @@ end c_sys5_re = PSB.build_system(PSITestSystems, "c_sys5_re"; add_reserves = true) model = DecisionModel(template, c_sys5_re) @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 360, 0, 72, 120, 72, false) + moi_tests(model, 360, 0, 72, 48, 72, false) end @testset "Test Reserves from with slack variables" begin From fa2bf00ac2d267ea41317f34577e58007142dafc Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:35 -0700 Subject: [PATCH 158/370] bring back hydro constructors --- src/PowerSimulations.jl | 3 + src/core/formulations.jl | 9 +- .../hydrogeneration_constructor.jl | 468 ++++++++++++++++++ .../devices/hydro_generation.jl | 297 +++++++++++ 4 files changed, 776 insertions(+), 1 deletion(-) create mode 100644 src/devices_models/device_constructors/hydrogeneration_constructor.jl create mode 100644 src/devices_models/devices/hydro_generation.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index f2c45c3dd4..41a1f0c63b 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -69,6 +69,7 @@ export ReserveLimitedRegulation ###### Hydro ####### export HydroDispatchRunOfRiver +export HydroCommitmentRunOfRiver # feedforward models export UpperBoundFeedforward @@ -528,6 +529,7 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") +include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") # Services Models @@ -549,6 +551,7 @@ include("initial_conditions/initialization.jl") # Device constructors include("devices_models/device_constructors/constructor_validations.jl") include("devices_models/device_constructors/thermalgeneration_constructor.jl") +include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 4916aef959..7522280c51 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -74,11 +74,18 @@ struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end ############################ Hydro Generation Formulations ################################# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end +abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end +abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ -struct HydroDispatchRunOfRiver <: AbstractHydroFormulation end +struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end + +""" +Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` +""" +struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl new file mode 100644 index 0000000000..75673eba77 --- /dev/null +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -0,0 +1,468 @@ +""" +Construct model for HydroGen with FixedOutput Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) + + # Expression + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + return +end + +function construct_device!( + ::OptimizationContainer, + ::PSY.System, + ::ModelConstructStage, + ::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} + # FixedOutput doesn't add any constraints to the model. This function covers + # AbstractPowerModel and AbstractActivePowerModel + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + # Expression + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + return +end + +""" +Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractPowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, ReactivePowerVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractPowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_constraints!( + container, + ReactivePowerVariableLimitsConstraint, + ReactivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + add_constraint_dual!(container, sys, model) + + return +end + +""" +Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation +with only Active Power. +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end + +""" +Construct model for HydroGen with RunOfRiver Commitment Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, ReactivePowerVariable, devices, D()) + add_variables!(container, OnVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_constraints!( + container, + ReactivePowerVariableLimitsConstraint, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end + +""" +Construct model for HydroGen with RunOfRiver Commitment Formulation +with only Active Power. +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: HydroCommitmentRunOfRiver, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, OnVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: HydroCommitmentRunOfRiver, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl new file mode 100644 index 0000000000..69e861b2c7 --- /dev/null +++ b/src/devices_models/devices/hydro_generation.jl @@ -0,0 +1,297 @@ +#! format: off +requires_initialization(::AbstractHydroFormulation) = false +requires_initialization(::AbstractHydroUnitCommitment) = true + +get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 +get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB +get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB + +########################### ActivePowerVariable, HydroGen ################################# +get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false +get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 +get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max + +############## ActivePowerVariable, HydroDispatchRunOfRiver #################### +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 + +############## ReactivePowerVariable, HydroGen #################### +get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false +get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power(d) +get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).min +get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).max + +############## OnVariable, HydroGen #################### +get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true +get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 + +########################### Parameter related set functions ################################ +get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) +get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) + +get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 +get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 +get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max +get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min + +#################### Initial Conditions for models ############### +initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) +initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() +initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) +initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() +initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 +initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() +initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) +initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() + +########################Objective Function################################################## +proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 +proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) +proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_surplus_cost(cost) +proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_shortage_cost(cost) + +objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::EnergySurplusVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_NEGATIVE +objective_function_multiplier(::EnergyShortageVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE + +sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE +sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE + +variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 +variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) +variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) + +#! format: on + +function get_initial_conditions_device_model( + ::OperationModel, + model::DeviceModel{T, <:AbstractHydroFormulation}, +) where {T <: PSY.HydroEnergyReservoir} + return model +end + +function get_initial_conditions_device_model( + ::OperationModel, + ::DeviceModel{T, <:AbstractHydroFormulation}, +) where {T <: PSY.HydroDispatch} + return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) +end + +function get_default_time_series_names( + ::Type{<:PSY.HydroGen}, + ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, +) + return Dict{Type{<:TimeSeriesParameter}, String}( + ActivePowerTimeSeriesParameter => "max_active_power", + ReactivePowerTimeSeriesParameter => "max_active_power", + ) +end + +function get_default_attributes( + ::Type{T}, + ::Type{D}, +) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} + return Dict{String, Any}("reservation" => false) +end + +""" +Time series constraints +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + add_parameterized_upper_bound_range_constraints( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + U, + ActivePowerTimeSeriesParameter, + devices, + model, + X, + ) + return +end + +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:RangeConstraintLBExpressions}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + return +end + +""" +Add semicontinuous range constraints for Hydro Unit Commitment formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + return +end + +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + add_parameterized_upper_bound_range_constraints( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + U, + ActivePowerTimeSeriesParameter, + devices, + model, + X, + ) + return +end + +""" +Min and max reactive Power Variable limits +""" +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ReactivePowerVariableLimitsConstraint}, + ::Type{<:AbstractHydroFormulation}, +) + return PSY.get_reactive_power_limits(x) +end + +""" +Min and max active Power Variable limits +""" +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ActivePowerVariableLimitsConstraint}, + ::Type{<:AbstractHydroFormulation}, +) + return PSY.get_active_power_limits(x) +end + +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ActivePowerVariableLimitsConstraint}, + ::Type{HydroDispatchRunOfRiver}, +) + return (min = 0.0, max = PSY.get_max_active_power(x)) +end + +""" +Add power variable limits constraints for hydro unit commitment formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{<:PowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + return +end + +""" +Add power variable limits constraints for hydro dispatch formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{<:PowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where { + V <: PSY.HydroGen, + W <: AbstractHydroDispatchFormulation, + X <: PM.AbstractPowerModel, +} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + return +end + +##################################### Auxillary Variables ############################ +function _calculate_aux_variable_value!( + container::OptimizationContainer, + ::AuxVarKey{EnergyOutput, T}, + system::PSY.System, + p_variable_results::JuMPVariableArray, +) where {T <: PSY.HydroGen} + devices = axes(p_variable_results, 1) + time_steps = get_time_steps(container) + resolution = get_resolution(container) + fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR + aux_variable_container = get_aux_variable(container, EnergyOutput(), T) + for name in devices, t in time_steps + aux_variable_container[name, t] = + jump_value(p_variable_results[name, t]) * fraction_of_hour + end + + return +end + +function calculate_aux_variable_value!( + container::OptimizationContainer, + aux_key::AuxVarKey{EnergyOutput, T}, + system::PSY.System, +) where {T <: PSY.HydroGen} + p_variable_results = get_variable(container, ActivePowerVariable(), T) + _calculate_aux_variable_value!( + container, + aux_key, + system, + p_variable_results, + ) + return +end + +##################################### Hydro generation cost ############################ +function objective_function!( + container::OptimizationContainer, + devices::IS.FlattenIteratorWrapper{T}, + ::DeviceModel{T, U}, + ::Type{<:PM.AbstractPowerModel}, +) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} + add_variable_cost!(container, ActivePowerVariable(), devices, U()) + add_proportional_cost!(container, OnVariable(), devices, U()) + return +end + +function objective_function!( + container::OptimizationContainer, + devices::IS.FlattenIteratorWrapper{T}, + ::DeviceModel{T, U}, + ::Type{<:PM.AbstractPowerModel}, +) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} + add_variable_cost!(container, ActivePowerVariable(), devices, U()) + return +end From 6016ee4b748f68e64714a2b06525ae11873c82ea Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:42 -0700 Subject: [PATCH 159/370] bring back hydro tests --- ...st_device_hydro_generation_constructors.jl | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 test/test_device_hydro_generation_constructors.jl diff --git a/test/test_device_hydro_generation_constructors.jl b/test/test_device_hydro_generation_constructors.jl new file mode 100644 index 0000000000..7545c57ace --- /dev/null +++ b/test/test_device_hydro_generation_constructors.jl @@ -0,0 +1,121 @@ +################################### +###### FIXED OUTPUT TESTS ######### +################################### + +@testset "Hydro DCPLossLess FixedOutput" begin + device_model = DeviceModel(HydroDispatch, FixedOutput) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 0, 0, 0, 0, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with FixedOutput formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, FixedOutput) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 0, 0, 0, 0, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +################################### +### RUN OF RIVER DISPATCH TESTS ### +################################### + +@testset "Hydro DCPLossLess HydroDispatch with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 24, 0, 48, 24, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroDispatch with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 72, 48, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 24, 0, 48, 24, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 72, 48, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +################################### +#### RUN OF RIVER COMMIT TESTS #### +################################### + +@testset "Hydro DCPLossLess HydroDispatch with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 48, 24, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroDispatch with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 72, 0, 72, 48, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 48, 24, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 72, 0, 72, 48, 0, true) + psi_checkobjfun_test(model, GAEVF) +end From e4b05fdee697203fe1ab41410fea1ade544bb919 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:57 -0700 Subject: [PATCH 160/370] remove reservoir budget from tests --- test/test_services_constructor.jl | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index f0ba76db4a..4fd3a477a1 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -132,6 +132,29 @@ end moi_tests(model, 360, 0, 72, 48, 72, false) end +@testset "Test Reserves from Hydro" begin + template = ProblemTemplate(CopperPlatePowerModel) + set_device_model!(template, PowerLoad, StaticPowerLoad) + set_device_model!(template, HydroEnergyReservoir, HydroDispatchRunOfRiver) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve5"), + ) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveDown}, RangeReserve, "Reserve6"), + ) + set_service_model!( + template, + ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), + ) + + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; add_reserves = true) + model = DecisionModel(template, c_sys5_hyd) + @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT + moi_tests(model, 240, 0, 48, 96, 72, false) +end + @testset "Test Reserves from with slack variables" begin template = get_thermal_dispatch_template_network( NetworkModel(CopperPlatePowerModel; use_slacks = true), From 03ca73ec8b560a96466823c50aa111f649776724 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 13:04:52 -0700 Subject: [PATCH 161/370] bring back hydro docs --- docs/make.jl | 1 + docs/src/formulation_library/General.md | 2 +- docs/src/formulation_library/HydroGen.md | 134 +++++++++++++++++++++++ 3 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 docs/src/formulation_library/HydroGen.md diff --git a/docs/make.jl b/docs/make.jl index 0a306e5e30..997ea23e72 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -34,6 +34,7 @@ pages = OrderedDict( "Formulation Library" => Any[ "General" => "formulation_library/General.md", "Thermal Generation" => "formulation_library/ThermalGen.md", + "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", diff --git a/docs/src/formulation_library/General.md b/docs/src/formulation_library/General.md index 0330f848f3..75ee8c70c2 100644 --- a/docs/src/formulation_library/General.md +++ b/docs/src/formulation_library/General.md @@ -29,7 +29,7 @@ using PowerSystems using DataFrames using Latexify combo_tables = [] -for t in [RenewableGen, ThermalGen, ElectricLoad] +for t in [RenewableGen, ThermalGen, HydroGen, ElectricLoad] combos = PowerSimulations.get_default_time_series_names(t, FixedOutput) combo_table = DataFrame( "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md new file mode 100644 index 0000000000..efe13982b3 --- /dev/null +++ b/docs/src/formulation_library/HydroGen.md @@ -0,0 +1,134 @@ +# `PowerSystems.HydroGen` Formulations + +Valid `DeviceModel`s for subtypes of `HydroGen` include the following: + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.generate_device_formulation_combinations() +filter!(x -> x["device_type"] <: HydroGen, combos) +combo_table = DataFrame( + "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], + "Device Type" => ["[$(c["device_type"])](https://nrel-siip.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], + "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], + ) +mdtable(combo_table, latex = false) +``` + +--- + +## `HydroDispatchRunOfRiver` + +```@docs +HydroDispatchRunOfRiver +``` + +**Variables:** + +- [`ActivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_active_power(device)` +- [`ReactivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_reactive_power(device)` + +**Static Parameters:** + +- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` +- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` +- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` + +**Time Series Parameters:** + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroDispatchRunOfRiver) +combo_table = DataFrame( + "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), + "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), + ) +mdtable(combo_table, latex = false) +``` + +**Objective:** + +Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg``. + +**Expressions:** + +Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) + +**Constraints:** + +```math +\begin{aligned} +& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ +& Qg^\text{min} \le Qg_t \le Qg^\text{max} +\end{aligned} +``` + +--- + +## `HydroCommitmentRunOfRiver` + +```@docs +HydroCommitmentRunOfRiver +``` + +**Variables:** + +- [`ActivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_active_power(device)` +- [`ReactivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_reactive_power(device)` +- [`OnVariable`](@ref): + - Bounds: {0, 1} + - Default initial value: `PowerSystems.get_status(device)` + +**Static Parameters:** + +- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` +- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` +- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` + +**Time Series Parameters:** + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroCommitmentRunOfRiver) +combo_table = DataFrame( + "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), + "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), + ) +mdtable(combo_table, latex = false) +``` + +**Objective:** + +Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. + +**Expressions:** + +Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) + +**Constraints:** + +```math +\begin{aligned} +& Pg_t \le Pg^\text{max}\\ +& Pg_t - u_t Pg^\text{max} \le 0 \\ +& Pg_t - u_t Pg^\text{min} \ge 0 \\ +& Qg_t - u_t Qg^\text{max} \le 0 \\ +& Qg_t - u_t Qg^\text{min} \ge 0 +\end{aligned} +``` \ No newline at end of file From 6af1dd7a0d9c47564370a8f41b25e52255e266e5 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 9 May 2023 11:57:38 -0600 Subject: [PATCH 162/370] remove code --- docs/make.jl | 1 - docs/src/formulation_library/General.md | 2 +- docs/src/formulation_library/HydroGen.md | 134 ----- src/core/formulations.jl | 7 - .../hydrogeneration_constructor.jl | 468 ------------------ .../devices/hydro_generation.jl | 297 ----------- ...st_device_hydro_generation_constructors.jl | 121 ----- test/test_services_constructor.jl | 23 - 8 files changed, 1 insertion(+), 1052 deletions(-) delete mode 100644 docs/src/formulation_library/HydroGen.md delete mode 100644 src/devices_models/device_constructors/hydrogeneration_constructor.jl delete mode 100644 src/devices_models/devices/hydro_generation.jl delete mode 100644 test/test_device_hydro_generation_constructors.jl diff --git a/docs/make.jl b/docs/make.jl index 997ea23e72..0a306e5e30 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -34,7 +34,6 @@ pages = OrderedDict( "Formulation Library" => Any[ "General" => "formulation_library/General.md", "Thermal Generation" => "formulation_library/ThermalGen.md", - "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", diff --git a/docs/src/formulation_library/General.md b/docs/src/formulation_library/General.md index 75ee8c70c2..0330f848f3 100644 --- a/docs/src/formulation_library/General.md +++ b/docs/src/formulation_library/General.md @@ -29,7 +29,7 @@ using PowerSystems using DataFrames using Latexify combo_tables = [] -for t in [RenewableGen, ThermalGen, HydroGen, ElectricLoad] +for t in [RenewableGen, ThermalGen, ElectricLoad] combos = PowerSimulations.get_default_time_series_names(t, FixedOutput) combo_table = DataFrame( "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md deleted file mode 100644 index efe13982b3..0000000000 --- a/docs/src/formulation_library/HydroGen.md +++ /dev/null @@ -1,134 +0,0 @@ -# `PowerSystems.HydroGen` Formulations - -Valid `DeviceModel`s for subtypes of `HydroGen` include the following: - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.generate_device_formulation_combinations() -filter!(x -> x["device_type"] <: HydroGen, combos) -combo_table = DataFrame( - "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], - "Device Type" => ["[$(c["device_type"])](https://nrel-siip.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], - "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], - ) -mdtable(combo_table, latex = false) -``` - ---- - -## `HydroDispatchRunOfRiver` - -```@docs -HydroDispatchRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroDispatchRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} -\end{aligned} -``` - ---- - -## `HydroCommitmentRunOfRiver` - -```@docs -HydroCommitmentRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroCommitmentRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg_t \le Pg^\text{max}\\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` \ No newline at end of file diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 7522280c51..948289a0e0 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -74,19 +74,12 @@ struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end ############################ Hydro Generation Formulations ################################# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end -abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end -abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end -""" -Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` -""" -struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end - ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end struct ReserveLimitedRegulation <: AbstractRegulationFormulation end diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl deleted file mode 100644 index 75673eba77..0000000000 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ /dev/null @@ -1,468 +0,0 @@ -""" -Construct model for HydroGen with FixedOutput Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -function construct_device!( - ::OptimizationContainer, - ::PSY.System, - ::ModelConstructStage, - ::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - # FixedOutput doesn't add any constraints to the model. This function covers - # AbstractPowerModel and AbstractActivePowerModel - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -""" -Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl deleted file mode 100644 index 69e861b2c7..0000000000 --- a/src/devices_models/devices/hydro_generation.jl +++ /dev/null @@ -1,297 +0,0 @@ -#! format: off -requires_initialization(::AbstractHydroFormulation) = false -requires_initialization(::AbstractHydroUnitCommitment) = true - -get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB - -########################### ActivePowerVariable, HydroGen ################################# -get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 -get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max - -############## ActivePowerVariable, HydroDispatchRunOfRiver #################### -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 - -############## ReactivePowerVariable, HydroGen #################### -get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power(d) -get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).min -get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).max - -############## OnVariable, HydroGen #################### -get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true -get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 - -########################### Parameter related set functions ################################ -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) - -get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min - -#################### Initial Conditions for models ############### -initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) -initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() -initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 -initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) -initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() - -########################Objective Function################################################## -proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 -proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_surplus_cost(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_shortage_cost(cost) - -objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::EnergySurplusVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_NEGATIVE -objective_function_multiplier(::EnergyShortageVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE - -sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE -sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE - -variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 -variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) -variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) - -#! format: on - -function get_initial_conditions_device_model( - ::OperationModel, - model::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroEnergyReservoir} - return model -end - -function get_initial_conditions_device_model( - ::OperationModel, - ::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroDispatch} - return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) -end - -function get_default_time_series_names( - ::Type{<:PSY.HydroGen}, - ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - ActivePowerTimeSeriesParameter => "max_active_power", - ReactivePowerTimeSeriesParameter => "max_active_power", - ) -end - -function get_default_attributes( - ::Type{T}, - ::Type{D}, -) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} - return Dict{String, Any}("reservation" => false) -end - -""" -Time series constraints -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:RangeConstraintLBExpressions}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -""" -Add semicontinuous range constraints for Hydro Unit Commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -""" -Min and max reactive Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ReactivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_reactive_power_limits(x) -end - -""" -Min and max active Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_active_power_limits(x) -end - -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchRunOfRiver}, -) - return (min = 0.0, max = PSY.get_max_active_power(x)) -end - -""" -Add power variable limits constraints for hydro unit commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -""" -Add power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroGen, - W <: AbstractHydroDispatchFormulation, - X <: PM.AbstractPowerModel, -} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -##################################### Auxillary Variables ############################ -function _calculate_aux_variable_value!( - container::OptimizationContainer, - ::AuxVarKey{EnergyOutput, T}, - system::PSY.System, - p_variable_results::JuMPVariableArray, -) where {T <: PSY.HydroGen} - devices = axes(p_variable_results, 1) - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - aux_variable_container = get_aux_variable(container, EnergyOutput(), T) - for name in devices, t in time_steps - aux_variable_container[name, t] = - jump_value(p_variable_results[name, t]) * fraction_of_hour - end - - return -end - -function calculate_aux_variable_value!( - container::OptimizationContainer, - aux_key::AuxVarKey{EnergyOutput, T}, - system::PSY.System, -) where {T <: PSY.HydroGen} - p_variable_results = get_variable(container, ActivePowerVariable(), T) - _calculate_aux_variable_value!( - container, - aux_key, - system, - p_variable_results, - ) - return -end - -##################################### Hydro generation cost ############################ -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, OnVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - return -end diff --git a/test/test_device_hydro_generation_constructors.jl b/test/test_device_hydro_generation_constructors.jl deleted file mode 100644 index 7545c57ace..0000000000 --- a/test/test_device_hydro_generation_constructors.jl +++ /dev/null @@ -1,121 +0,0 @@ -################################### -###### FIXED OUTPUT TESTS ######### -################################### - -@testset "Hydro DCPLossLess FixedOutput" begin - device_model = DeviceModel(HydroDispatch, FixedOutput) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with FixedOutput formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, FixedOutput) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -### RUN OF RIVER DISPATCH TESTS ### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -#### RUN OF RIVER COMMIT TESTS #### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index 4fd3a477a1..f0ba76db4a 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -132,29 +132,6 @@ end moi_tests(model, 360, 0, 72, 48, 72, false) end -@testset "Test Reserves from Hydro" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, PowerLoad, StaticPowerLoad) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchRunOfRiver) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve5"), - ) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveDown}, RangeReserve, "Reserve6"), - ) - set_service_model!( - template, - ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), - ) - - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; add_reserves = true) - model = DecisionModel(template, c_sys5_hyd) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 240, 0, 48, 96, 72, false) -end - @testset "Test Reserves from with slack variables" begin template = get_thermal_dispatch_template_network( NetworkModel(CopperPlatePowerModel; use_slacks = true), From 58fd05994dbd4a35857cff142a49b83a34a46539 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 25 Apr 2023 13:59:51 -0600 Subject: [PATCH 163/370] move more code --- src/PowerSimulations.jl | 3 --- src/core/formulations.jl | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 41a1f0c63b..f2c45c3dd4 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -69,7 +69,6 @@ export ReserveLimitedRegulation ###### Hydro ####### export HydroDispatchRunOfRiver -export HydroCommitmentRunOfRiver # feedforward models export UpperBoundFeedforward @@ -529,7 +528,6 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") -include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") # Services Models @@ -551,7 +549,6 @@ include("initial_conditions/initialization.jl") # Device constructors include("devices_models/device_constructors/constructor_validations.jl") include("devices_models/device_constructors/thermalgeneration_constructor.jl") -include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 948289a0e0..4916aef959 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -78,7 +78,7 @@ abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ -struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end +struct HydroDispatchRunOfRiver <: AbstractHydroFormulation end ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end From 907df8a1883f097225e68b94502cc967f1789b5a Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:35 -0700 Subject: [PATCH 164/370] bring back hydro constructors --- src/PowerSimulations.jl | 3 + src/core/formulations.jl | 9 +- .../hydrogeneration_constructor.jl | 468 ++++++++++++++++++ .../devices/hydro_generation.jl | 297 +++++++++++ 4 files changed, 776 insertions(+), 1 deletion(-) create mode 100644 src/devices_models/device_constructors/hydrogeneration_constructor.jl create mode 100644 src/devices_models/devices/hydro_generation.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index f2c45c3dd4..41a1f0c63b 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -69,6 +69,7 @@ export ReserveLimitedRegulation ###### Hydro ####### export HydroDispatchRunOfRiver +export HydroCommitmentRunOfRiver # feedforward models export UpperBoundFeedforward @@ -528,6 +529,7 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") +include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") # Services Models @@ -549,6 +551,7 @@ include("initial_conditions/initialization.jl") # Device constructors include("devices_models/device_constructors/constructor_validations.jl") include("devices_models/device_constructors/thermalgeneration_constructor.jl") +include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 4916aef959..7522280c51 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -74,11 +74,18 @@ struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end ############################ Hydro Generation Formulations ################################# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end +abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end +abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ -struct HydroDispatchRunOfRiver <: AbstractHydroFormulation end +struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end + +""" +Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` +""" +struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl new file mode 100644 index 0000000000..75673eba77 --- /dev/null +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -0,0 +1,468 @@ +""" +Construct model for HydroGen with FixedOutput Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) + + # Expression + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + return +end + +function construct_device!( + ::OptimizationContainer, + ::PSY.System, + ::ModelConstructStage, + ::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} + # FixedOutput doesn't add any constraints to the model. This function covers + # AbstractPowerModel and AbstractActivePowerModel + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + # Expression + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + return +end + +""" +Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractPowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, ReactivePowerVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractPowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_constraints!( + container, + ReactivePowerVariableLimitsConstraint, + ReactivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + add_constraint_dual!(container, sys, model) + + return +end + +""" +Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation +with only Active Power. +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end + +""" +Construct model for HydroGen with RunOfRiver Commitment Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, ReactivePowerVariable, devices, D()) + add_variables!(container, OnVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_constraints!( + container, + ReactivePowerVariableLimitsConstraint, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end + +""" +Construct model for HydroGen with RunOfRiver Commitment Formulation +with only Active Power. +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: HydroCommitmentRunOfRiver, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, OnVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: HydroCommitmentRunOfRiver, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl new file mode 100644 index 0000000000..69e861b2c7 --- /dev/null +++ b/src/devices_models/devices/hydro_generation.jl @@ -0,0 +1,297 @@ +#! format: off +requires_initialization(::AbstractHydroFormulation) = false +requires_initialization(::AbstractHydroUnitCommitment) = true + +get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 +get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB +get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB + +########################### ActivePowerVariable, HydroGen ################################# +get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false +get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 +get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max + +############## ActivePowerVariable, HydroDispatchRunOfRiver #################### +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 + +############## ReactivePowerVariable, HydroGen #################### +get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false +get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power(d) +get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).min +get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).max + +############## OnVariable, HydroGen #################### +get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true +get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 + +########################### Parameter related set functions ################################ +get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) +get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) + +get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 +get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 +get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max +get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min + +#################### Initial Conditions for models ############### +initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) +initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() +initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) +initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() +initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 +initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() +initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) +initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() + +########################Objective Function################################################## +proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 +proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) +proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_surplus_cost(cost) +proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_shortage_cost(cost) + +objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::EnergySurplusVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_NEGATIVE +objective_function_multiplier(::EnergyShortageVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE + +sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE +sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE + +variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 +variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) +variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) + +#! format: on + +function get_initial_conditions_device_model( + ::OperationModel, + model::DeviceModel{T, <:AbstractHydroFormulation}, +) where {T <: PSY.HydroEnergyReservoir} + return model +end + +function get_initial_conditions_device_model( + ::OperationModel, + ::DeviceModel{T, <:AbstractHydroFormulation}, +) where {T <: PSY.HydroDispatch} + return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) +end + +function get_default_time_series_names( + ::Type{<:PSY.HydroGen}, + ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, +) + return Dict{Type{<:TimeSeriesParameter}, String}( + ActivePowerTimeSeriesParameter => "max_active_power", + ReactivePowerTimeSeriesParameter => "max_active_power", + ) +end + +function get_default_attributes( + ::Type{T}, + ::Type{D}, +) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} + return Dict{String, Any}("reservation" => false) +end + +""" +Time series constraints +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + add_parameterized_upper_bound_range_constraints( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + U, + ActivePowerTimeSeriesParameter, + devices, + model, + X, + ) + return +end + +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:RangeConstraintLBExpressions}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + return +end + +""" +Add semicontinuous range constraints for Hydro Unit Commitment formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + return +end + +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + add_parameterized_upper_bound_range_constraints( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + U, + ActivePowerTimeSeriesParameter, + devices, + model, + X, + ) + return +end + +""" +Min and max reactive Power Variable limits +""" +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ReactivePowerVariableLimitsConstraint}, + ::Type{<:AbstractHydroFormulation}, +) + return PSY.get_reactive_power_limits(x) +end + +""" +Min and max active Power Variable limits +""" +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ActivePowerVariableLimitsConstraint}, + ::Type{<:AbstractHydroFormulation}, +) + return PSY.get_active_power_limits(x) +end + +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ActivePowerVariableLimitsConstraint}, + ::Type{HydroDispatchRunOfRiver}, +) + return (min = 0.0, max = PSY.get_max_active_power(x)) +end + +""" +Add power variable limits constraints for hydro unit commitment formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{<:PowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + return +end + +""" +Add power variable limits constraints for hydro dispatch formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{<:PowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where { + V <: PSY.HydroGen, + W <: AbstractHydroDispatchFormulation, + X <: PM.AbstractPowerModel, +} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + return +end + +##################################### Auxillary Variables ############################ +function _calculate_aux_variable_value!( + container::OptimizationContainer, + ::AuxVarKey{EnergyOutput, T}, + system::PSY.System, + p_variable_results::JuMPVariableArray, +) where {T <: PSY.HydroGen} + devices = axes(p_variable_results, 1) + time_steps = get_time_steps(container) + resolution = get_resolution(container) + fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR + aux_variable_container = get_aux_variable(container, EnergyOutput(), T) + for name in devices, t in time_steps + aux_variable_container[name, t] = + jump_value(p_variable_results[name, t]) * fraction_of_hour + end + + return +end + +function calculate_aux_variable_value!( + container::OptimizationContainer, + aux_key::AuxVarKey{EnergyOutput, T}, + system::PSY.System, +) where {T <: PSY.HydroGen} + p_variable_results = get_variable(container, ActivePowerVariable(), T) + _calculate_aux_variable_value!( + container, + aux_key, + system, + p_variable_results, + ) + return +end + +##################################### Hydro generation cost ############################ +function objective_function!( + container::OptimizationContainer, + devices::IS.FlattenIteratorWrapper{T}, + ::DeviceModel{T, U}, + ::Type{<:PM.AbstractPowerModel}, +) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} + add_variable_cost!(container, ActivePowerVariable(), devices, U()) + add_proportional_cost!(container, OnVariable(), devices, U()) + return +end + +function objective_function!( + container::OptimizationContainer, + devices::IS.FlattenIteratorWrapper{T}, + ::DeviceModel{T, U}, + ::Type{<:PM.AbstractPowerModel}, +) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} + add_variable_cost!(container, ActivePowerVariable(), devices, U()) + return +end From 0dee597e003d774ec17454fe01adbdfe1b6633bc Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:42 -0700 Subject: [PATCH 165/370] bring back hydro tests --- ...st_device_hydro_generation_constructors.jl | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 test/test_device_hydro_generation_constructors.jl diff --git a/test/test_device_hydro_generation_constructors.jl b/test/test_device_hydro_generation_constructors.jl new file mode 100644 index 0000000000..7545c57ace --- /dev/null +++ b/test/test_device_hydro_generation_constructors.jl @@ -0,0 +1,121 @@ +################################### +###### FIXED OUTPUT TESTS ######### +################################### + +@testset "Hydro DCPLossLess FixedOutput" begin + device_model = DeviceModel(HydroDispatch, FixedOutput) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 0, 0, 0, 0, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with FixedOutput formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, FixedOutput) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 0, 0, 0, 0, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +################################### +### RUN OF RIVER DISPATCH TESTS ### +################################### + +@testset "Hydro DCPLossLess HydroDispatch with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 24, 0, 48, 24, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroDispatch with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 72, 48, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 24, 0, 48, 24, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 72, 48, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +################################### +#### RUN OF RIVER COMMIT TESTS #### +################################### + +@testset "Hydro DCPLossLess HydroDispatch with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 48, 24, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroDispatch with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 72, 0, 72, 48, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 48, 24, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 72, 0, 72, 48, 0, true) + psi_checkobjfun_test(model, GAEVF) +end From 4390c0babe40d8075a910216da286dabcdb19a71 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:57 -0700 Subject: [PATCH 166/370] remove reservoir budget from tests --- test/test_services_constructor.jl | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index f0ba76db4a..4fd3a477a1 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -132,6 +132,29 @@ end moi_tests(model, 360, 0, 72, 48, 72, false) end +@testset "Test Reserves from Hydro" begin + template = ProblemTemplate(CopperPlatePowerModel) + set_device_model!(template, PowerLoad, StaticPowerLoad) + set_device_model!(template, HydroEnergyReservoir, HydroDispatchRunOfRiver) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve5"), + ) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveDown}, RangeReserve, "Reserve6"), + ) + set_service_model!( + template, + ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), + ) + + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; add_reserves = true) + model = DecisionModel(template, c_sys5_hyd) + @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT + moi_tests(model, 240, 0, 48, 96, 72, false) +end + @testset "Test Reserves from with slack variables" begin template = get_thermal_dispatch_template_network( NetworkModel(CopperPlatePowerModel; use_slacks = true), From a75bf25328b9fc9431cf2bf121df2c9892fb7b71 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 13:04:52 -0700 Subject: [PATCH 167/370] bring back hydro docs --- docs/make.jl | 1 + docs/src/formulation_library/General.md | 2 +- docs/src/formulation_library/HydroGen.md | 134 +++++++++++++++++++++++ 3 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 docs/src/formulation_library/HydroGen.md diff --git a/docs/make.jl b/docs/make.jl index 0a306e5e30..997ea23e72 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -34,6 +34,7 @@ pages = OrderedDict( "Formulation Library" => Any[ "General" => "formulation_library/General.md", "Thermal Generation" => "formulation_library/ThermalGen.md", + "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", diff --git a/docs/src/formulation_library/General.md b/docs/src/formulation_library/General.md index 0330f848f3..75ee8c70c2 100644 --- a/docs/src/formulation_library/General.md +++ b/docs/src/formulation_library/General.md @@ -29,7 +29,7 @@ using PowerSystems using DataFrames using Latexify combo_tables = [] -for t in [RenewableGen, ThermalGen, ElectricLoad] +for t in [RenewableGen, ThermalGen, HydroGen, ElectricLoad] combos = PowerSimulations.get_default_time_series_names(t, FixedOutput) combo_table = DataFrame( "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md new file mode 100644 index 0000000000..efe13982b3 --- /dev/null +++ b/docs/src/formulation_library/HydroGen.md @@ -0,0 +1,134 @@ +# `PowerSystems.HydroGen` Formulations + +Valid `DeviceModel`s for subtypes of `HydroGen` include the following: + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.generate_device_formulation_combinations() +filter!(x -> x["device_type"] <: HydroGen, combos) +combo_table = DataFrame( + "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], + "Device Type" => ["[$(c["device_type"])](https://nrel-siip.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], + "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], + ) +mdtable(combo_table, latex = false) +``` + +--- + +## `HydroDispatchRunOfRiver` + +```@docs +HydroDispatchRunOfRiver +``` + +**Variables:** + +- [`ActivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_active_power(device)` +- [`ReactivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_reactive_power(device)` + +**Static Parameters:** + +- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` +- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` +- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` + +**Time Series Parameters:** + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroDispatchRunOfRiver) +combo_table = DataFrame( + "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), + "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), + ) +mdtable(combo_table, latex = false) +``` + +**Objective:** + +Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg``. + +**Expressions:** + +Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) + +**Constraints:** + +```math +\begin{aligned} +& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ +& Qg^\text{min} \le Qg_t \le Qg^\text{max} +\end{aligned} +``` + +--- + +## `HydroCommitmentRunOfRiver` + +```@docs +HydroCommitmentRunOfRiver +``` + +**Variables:** + +- [`ActivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_active_power(device)` +- [`ReactivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_reactive_power(device)` +- [`OnVariable`](@ref): + - Bounds: {0, 1} + - Default initial value: `PowerSystems.get_status(device)` + +**Static Parameters:** + +- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` +- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` +- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` + +**Time Series Parameters:** + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroCommitmentRunOfRiver) +combo_table = DataFrame( + "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), + "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), + ) +mdtable(combo_table, latex = false) +``` + +**Objective:** + +Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. + +**Expressions:** + +Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) + +**Constraints:** + +```math +\begin{aligned} +& Pg_t \le Pg^\text{max}\\ +& Pg_t - u_t Pg^\text{max} \le 0 \\ +& Pg_t - u_t Pg^\text{min} \ge 0 \\ +& Qg_t - u_t Qg^\text{max} \le 0 \\ +& Qg_t - u_t Qg^\text{min} \ge 0 +\end{aligned} +``` \ No newline at end of file From 9c0ddeb67d4e86fe649b64e6c493d0e0c9fc7e00 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 9 May 2023 11:57:38 -0600 Subject: [PATCH 168/370] remove code --- docs/make.jl | 1 - docs/src/formulation_library/General.md | 2 +- docs/src/formulation_library/HydroGen.md | 134 ----- src/core/formulations.jl | 7 - .../hydrogeneration_constructor.jl | 468 ------------------ .../devices/hydro_generation.jl | 297 ----------- ...st_device_hydro_generation_constructors.jl | 121 ----- test/test_services_constructor.jl | 23 - 8 files changed, 1 insertion(+), 1052 deletions(-) delete mode 100644 docs/src/formulation_library/HydroGen.md delete mode 100644 src/devices_models/device_constructors/hydrogeneration_constructor.jl delete mode 100644 src/devices_models/devices/hydro_generation.jl delete mode 100644 test/test_device_hydro_generation_constructors.jl diff --git a/docs/make.jl b/docs/make.jl index 997ea23e72..0a306e5e30 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -34,7 +34,6 @@ pages = OrderedDict( "Formulation Library" => Any[ "General" => "formulation_library/General.md", "Thermal Generation" => "formulation_library/ThermalGen.md", - "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", diff --git a/docs/src/formulation_library/General.md b/docs/src/formulation_library/General.md index 75ee8c70c2..0330f848f3 100644 --- a/docs/src/formulation_library/General.md +++ b/docs/src/formulation_library/General.md @@ -29,7 +29,7 @@ using PowerSystems using DataFrames using Latexify combo_tables = [] -for t in [RenewableGen, ThermalGen, HydroGen, ElectricLoad] +for t in [RenewableGen, ThermalGen, ElectricLoad] combos = PowerSimulations.get_default_time_series_names(t, FixedOutput) combo_table = DataFrame( "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md deleted file mode 100644 index efe13982b3..0000000000 --- a/docs/src/formulation_library/HydroGen.md +++ /dev/null @@ -1,134 +0,0 @@ -# `PowerSystems.HydroGen` Formulations - -Valid `DeviceModel`s for subtypes of `HydroGen` include the following: - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.generate_device_formulation_combinations() -filter!(x -> x["device_type"] <: HydroGen, combos) -combo_table = DataFrame( - "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], - "Device Type" => ["[$(c["device_type"])](https://nrel-siip.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], - "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], - ) -mdtable(combo_table, latex = false) -``` - ---- - -## `HydroDispatchRunOfRiver` - -```@docs -HydroDispatchRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroDispatchRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} -\end{aligned} -``` - ---- - -## `HydroCommitmentRunOfRiver` - -```@docs -HydroCommitmentRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroCommitmentRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg_t \le Pg^\text{max}\\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` \ No newline at end of file diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 7522280c51..948289a0e0 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -74,19 +74,12 @@ struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end ############################ Hydro Generation Formulations ################################# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end -abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end -abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end -""" -Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` -""" -struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end - ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end struct ReserveLimitedRegulation <: AbstractRegulationFormulation end diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl deleted file mode 100644 index 75673eba77..0000000000 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ /dev/null @@ -1,468 +0,0 @@ -""" -Construct model for HydroGen with FixedOutput Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -function construct_device!( - ::OptimizationContainer, - ::PSY.System, - ::ModelConstructStage, - ::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - # FixedOutput doesn't add any constraints to the model. This function covers - # AbstractPowerModel and AbstractActivePowerModel - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -""" -Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl deleted file mode 100644 index 69e861b2c7..0000000000 --- a/src/devices_models/devices/hydro_generation.jl +++ /dev/null @@ -1,297 +0,0 @@ -#! format: off -requires_initialization(::AbstractHydroFormulation) = false -requires_initialization(::AbstractHydroUnitCommitment) = true - -get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB - -########################### ActivePowerVariable, HydroGen ################################# -get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 -get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max - -############## ActivePowerVariable, HydroDispatchRunOfRiver #################### -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 - -############## ReactivePowerVariable, HydroGen #################### -get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power(d) -get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).min -get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).max - -############## OnVariable, HydroGen #################### -get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true -get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 - -########################### Parameter related set functions ################################ -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) - -get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min - -#################### Initial Conditions for models ############### -initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) -initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() -initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 -initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) -initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() - -########################Objective Function################################################## -proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 -proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_surplus_cost(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_shortage_cost(cost) - -objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::EnergySurplusVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_NEGATIVE -objective_function_multiplier(::EnergyShortageVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE - -sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE -sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE - -variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 -variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) -variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) - -#! format: on - -function get_initial_conditions_device_model( - ::OperationModel, - model::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroEnergyReservoir} - return model -end - -function get_initial_conditions_device_model( - ::OperationModel, - ::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroDispatch} - return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) -end - -function get_default_time_series_names( - ::Type{<:PSY.HydroGen}, - ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - ActivePowerTimeSeriesParameter => "max_active_power", - ReactivePowerTimeSeriesParameter => "max_active_power", - ) -end - -function get_default_attributes( - ::Type{T}, - ::Type{D}, -) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} - return Dict{String, Any}("reservation" => false) -end - -""" -Time series constraints -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:RangeConstraintLBExpressions}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -""" -Add semicontinuous range constraints for Hydro Unit Commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -""" -Min and max reactive Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ReactivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_reactive_power_limits(x) -end - -""" -Min and max active Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_active_power_limits(x) -end - -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchRunOfRiver}, -) - return (min = 0.0, max = PSY.get_max_active_power(x)) -end - -""" -Add power variable limits constraints for hydro unit commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -""" -Add power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroGen, - W <: AbstractHydroDispatchFormulation, - X <: PM.AbstractPowerModel, -} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -##################################### Auxillary Variables ############################ -function _calculate_aux_variable_value!( - container::OptimizationContainer, - ::AuxVarKey{EnergyOutput, T}, - system::PSY.System, - p_variable_results::JuMPVariableArray, -) where {T <: PSY.HydroGen} - devices = axes(p_variable_results, 1) - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - aux_variable_container = get_aux_variable(container, EnergyOutput(), T) - for name in devices, t in time_steps - aux_variable_container[name, t] = - jump_value(p_variable_results[name, t]) * fraction_of_hour - end - - return -end - -function calculate_aux_variable_value!( - container::OptimizationContainer, - aux_key::AuxVarKey{EnergyOutput, T}, - system::PSY.System, -) where {T <: PSY.HydroGen} - p_variable_results = get_variable(container, ActivePowerVariable(), T) - _calculate_aux_variable_value!( - container, - aux_key, - system, - p_variable_results, - ) - return -end - -##################################### Hydro generation cost ############################ -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, OnVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - return -end diff --git a/test/test_device_hydro_generation_constructors.jl b/test/test_device_hydro_generation_constructors.jl deleted file mode 100644 index 7545c57ace..0000000000 --- a/test/test_device_hydro_generation_constructors.jl +++ /dev/null @@ -1,121 +0,0 @@ -################################### -###### FIXED OUTPUT TESTS ######### -################################### - -@testset "Hydro DCPLossLess FixedOutput" begin - device_model = DeviceModel(HydroDispatch, FixedOutput) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with FixedOutput formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, FixedOutput) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -### RUN OF RIVER DISPATCH TESTS ### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -#### RUN OF RIVER COMMIT TESTS #### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index 4fd3a477a1..f0ba76db4a 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -132,29 +132,6 @@ end moi_tests(model, 360, 0, 72, 48, 72, false) end -@testset "Test Reserves from Hydro" begin - template = ProblemTemplate(CopperPlatePowerModel) - set_device_model!(template, PowerLoad, StaticPowerLoad) - set_device_model!(template, HydroEnergyReservoir, HydroDispatchRunOfRiver) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve5"), - ) - set_service_model!( - template, - ServiceModel(VariableReserve{ReserveDown}, RangeReserve, "Reserve6"), - ) - set_service_model!( - template, - ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), - ) - - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; add_reserves = true) - model = DecisionModel(template, c_sys5_hyd) - @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 240, 0, 48, 96, 72, false) -end - @testset "Test Reserves from with slack variables" begin template = get_thermal_dispatch_template_network( NetworkModel(CopperPlatePowerModel; use_slacks = true), From 94428ef7695b016704f58238765a2b26dfe3e963 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 25 Apr 2023 13:59:51 -0600 Subject: [PATCH 169/370] move more code --- src/PowerSimulations.jl | 3 --- src/core/formulations.jl | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 41a1f0c63b..f2c45c3dd4 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -69,7 +69,6 @@ export ReserveLimitedRegulation ###### Hydro ####### export HydroDispatchRunOfRiver -export HydroCommitmentRunOfRiver # feedforward models export UpperBoundFeedforward @@ -529,7 +528,6 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") -include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") # Services Models @@ -551,7 +549,6 @@ include("initial_conditions/initialization.jl") # Device constructors include("devices_models/device_constructors/constructor_validations.jl") include("devices_models/device_constructors/thermalgeneration_constructor.jl") -include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 948289a0e0..4916aef959 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -78,7 +78,7 @@ abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ -struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end +struct HydroDispatchRunOfRiver <: AbstractHydroFormulation end ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end From 810ff0aa2429a0224e80bf3fe7f68b7dabf4a467 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:35 -0700 Subject: [PATCH 170/370] bring back hydro constructors --- src/PowerSimulations.jl | 3 + src/core/formulations.jl | 9 +- .../hydrogeneration_constructor.jl | 468 ++++++++++++++++++ .../devices/hydro_generation.jl | 297 +++++++++++ 4 files changed, 776 insertions(+), 1 deletion(-) create mode 100644 src/devices_models/device_constructors/hydrogeneration_constructor.jl create mode 100644 src/devices_models/devices/hydro_generation.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index f2c45c3dd4..41a1f0c63b 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -69,6 +69,7 @@ export ReserveLimitedRegulation ###### Hydro ####### export HydroDispatchRunOfRiver +export HydroCommitmentRunOfRiver # feedforward models export UpperBoundFeedforward @@ -528,6 +529,7 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") +include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") # Services Models @@ -549,6 +551,7 @@ include("initial_conditions/initialization.jl") # Device constructors include("devices_models/device_constructors/constructor_validations.jl") include("devices_models/device_constructors/thermalgeneration_constructor.jl") +include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 4916aef959..7522280c51 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -74,11 +74,18 @@ struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end ############################ Hydro Generation Formulations ################################# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end +abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end +abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end """ Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` """ -struct HydroDispatchRunOfRiver <: AbstractHydroFormulation end +struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end + +""" +Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` +""" +struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl new file mode 100644 index 0000000000..75673eba77 --- /dev/null +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -0,0 +1,468 @@ +""" +Construct model for HydroGen with FixedOutput Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) + + # Expression + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + return +end + +function construct_device!( + ::OptimizationContainer, + ::PSY.System, + ::ModelConstructStage, + ::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} + # FixedOutput doesn't add any constraints to the model. This function covers + # AbstractPowerModel and AbstractActivePowerModel + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, FixedOutput}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + # Expression + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerTimeSeriesParameter, + devices, + model, + network_model, + ) + return +end + +""" +Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractPowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, ReactivePowerVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractPowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_constraints!( + container, + ReactivePowerVariableLimitsConstraint, + ReactivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + add_constraint_dual!(container, sys, model) + + return +end + +""" +Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation +with only Active Power. +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: AbstractHydroDispatchFormulation, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end + +""" +Construct model for HydroGen with RunOfRiver Commitment Formulation +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, ReactivePowerVariable, devices, D()) + add_variables!(container, OnVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_to_expression!( + container, + ReactivePowerBalance, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_constraints!( + container, + ReactivePowerVariableLimitsConstraint, + ReactivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end + +""" +Construct model for HydroGen with RunOfRiver Commitment Formulation +with only Active Power. +""" +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: HydroCommitmentRunOfRiver, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_variables!(container, ActivePowerVariable, devices, D()) + add_variables!(container, OnVariable, devices, D()) + add_variables!(container, EnergyOutput, devices, D()) + add_to_expression!( + container, + ActivePowerBalance, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_expressions!(container, ProductionCostExpression, devices, model) + + add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) + add_to_expression!( + container, + ActivePowerRangeExpressionLB, + ActivePowerVariable, + devices, + model, + network_model, + ) + add_to_expression!( + container, + ActivePowerRangeExpressionUB, + ActivePowerVariable, + devices, + model, + network_model, + ) + + add_feedforward_arguments!(container, model, devices) + return +end + +function construct_device!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::DeviceModel{H, D}, + network_model::NetworkModel{S}, +) where { + H <: PSY.HydroGen, + D <: HydroCommitmentRunOfRiver, + S <: PM.AbstractActivePowerModel, +} + devices = + get_available_components(H, sys, get_attribute(model, "filter_function")) + + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionLB, + devices, + model, + network_model, + ) + add_constraints!( + container, + ActivePowerVariableLimitsConstraint, + ActivePowerRangeExpressionUB, + devices, + model, + network_model, + ) + + add_feedforward_constraints!(container, model, devices) + + objective_function!(container, devices, model, S) + + add_constraint_dual!(container, sys, model) + return +end diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl new file mode 100644 index 0000000000..69e861b2c7 --- /dev/null +++ b/src/devices_models/devices/hydro_generation.jl @@ -0,0 +1,297 @@ +#! format: off +requires_initialization(::AbstractHydroFormulation) = false +requires_initialization(::AbstractHydroUnitCommitment) = true + +get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 +get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB +get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB + +########################### ActivePowerVariable, HydroGen ################################# +get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false +get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 +get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max + +############## ActivePowerVariable, HydroDispatchRunOfRiver #################### +get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 + +############## ReactivePowerVariable, HydroGen #################### +get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false +get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power(d) +get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).min +get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).max + +############## OnVariable, HydroGen #################### +get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true +get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 + +########################### Parameter related set functions ################################ +get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) +get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) + +get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 +get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 +get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max +get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min + +#################### Initial Conditions for models ############### +initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) +initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() +initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) +initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() +initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 +initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() +initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) +initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() + +########################Objective Function################################################## +proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 +proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) +proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_surplus_cost(cost) +proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_shortage_cost(cost) + +objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +objective_function_multiplier(::EnergySurplusVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_NEGATIVE +objective_function_multiplier(::EnergyShortageVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE + +sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE +sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE + +variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 +variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) +variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) + +#! format: on + +function get_initial_conditions_device_model( + ::OperationModel, + model::DeviceModel{T, <:AbstractHydroFormulation}, +) where {T <: PSY.HydroEnergyReservoir} + return model +end + +function get_initial_conditions_device_model( + ::OperationModel, + ::DeviceModel{T, <:AbstractHydroFormulation}, +) where {T <: PSY.HydroDispatch} + return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) +end + +function get_default_time_series_names( + ::Type{<:PSY.HydroGen}, + ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, +) + return Dict{Type{<:TimeSeriesParameter}, String}( + ActivePowerTimeSeriesParameter => "max_active_power", + ReactivePowerTimeSeriesParameter => "max_active_power", + ) +end + +function get_default_attributes( + ::Type{T}, + ::Type{D}, +) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} + return Dict{String, Any}("reservation" => false) +end + +""" +Time series constraints +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + add_parameterized_upper_bound_range_constraints( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + U, + ActivePowerTimeSeriesParameter, + devices, + model, + X, + ) + return +end + +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:RangeConstraintLBExpressions}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + return +end + +""" +Add semicontinuous range constraints for Hydro Unit Commitment formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + return +end + +function add_constraints!( + container::OptimizationContainer, + T::Type{ActivePowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + add_parameterized_upper_bound_range_constraints( + container, + ActivePowerVariableTimeSeriesLimitsConstraint, + U, + ActivePowerTimeSeriesParameter, + devices, + model, + X, + ) + return +end + +""" +Min and max reactive Power Variable limits +""" +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ReactivePowerVariableLimitsConstraint}, + ::Type{<:AbstractHydroFormulation}, +) + return PSY.get_reactive_power_limits(x) +end + +""" +Min and max active Power Variable limits +""" +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ActivePowerVariableLimitsConstraint}, + ::Type{<:AbstractHydroFormulation}, +) + return PSY.get_active_power_limits(x) +end + +function get_min_max_limits( + x::PSY.HydroGen, + ::Type{<:ActivePowerVariableLimitsConstraint}, + ::Type{HydroDispatchRunOfRiver}, +) + return (min = 0.0, max = PSY.get_max_active_power(x)) +end + +""" +Add power variable limits constraints for hydro unit commitment formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{<:PowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} + add_semicontinuous_range_constraints!(container, T, U, devices, model, X) + return +end + +""" +Add power variable limits constraints for hydro dispatch formulation +""" +function add_constraints!( + container::OptimizationContainer, + T::Type{<:PowerVariableLimitsConstraint}, + U::Type{<:Union{VariableType, ExpressionType}}, + devices::IS.FlattenIteratorWrapper{V}, + model::DeviceModel{V, W}, + ::NetworkModel{X}, +) where { + V <: PSY.HydroGen, + W <: AbstractHydroDispatchFormulation, + X <: PM.AbstractPowerModel, +} + if !has_semicontinuous_feedforward(model, U) + add_range_constraints!(container, T, U, devices, model, X) + end + return +end + +##################################### Auxillary Variables ############################ +function _calculate_aux_variable_value!( + container::OptimizationContainer, + ::AuxVarKey{EnergyOutput, T}, + system::PSY.System, + p_variable_results::JuMPVariableArray, +) where {T <: PSY.HydroGen} + devices = axes(p_variable_results, 1) + time_steps = get_time_steps(container) + resolution = get_resolution(container) + fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR + aux_variable_container = get_aux_variable(container, EnergyOutput(), T) + for name in devices, t in time_steps + aux_variable_container[name, t] = + jump_value(p_variable_results[name, t]) * fraction_of_hour + end + + return +end + +function calculate_aux_variable_value!( + container::OptimizationContainer, + aux_key::AuxVarKey{EnergyOutput, T}, + system::PSY.System, +) where {T <: PSY.HydroGen} + p_variable_results = get_variable(container, ActivePowerVariable(), T) + _calculate_aux_variable_value!( + container, + aux_key, + system, + p_variable_results, + ) + return +end + +##################################### Hydro generation cost ############################ +function objective_function!( + container::OptimizationContainer, + devices::IS.FlattenIteratorWrapper{T}, + ::DeviceModel{T, U}, + ::Type{<:PM.AbstractPowerModel}, +) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} + add_variable_cost!(container, ActivePowerVariable(), devices, U()) + add_proportional_cost!(container, OnVariable(), devices, U()) + return +end + +function objective_function!( + container::OptimizationContainer, + devices::IS.FlattenIteratorWrapper{T}, + ::DeviceModel{T, U}, + ::Type{<:PM.AbstractPowerModel}, +) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} + add_variable_cost!(container, ActivePowerVariable(), devices, U()) + return +end From 898c51562f4f219865873c2572ea07f9abe1ce83 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:42 -0700 Subject: [PATCH 171/370] bring back hydro tests --- ...st_device_hydro_generation_constructors.jl | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 test/test_device_hydro_generation_constructors.jl diff --git a/test/test_device_hydro_generation_constructors.jl b/test/test_device_hydro_generation_constructors.jl new file mode 100644 index 0000000000..7545c57ace --- /dev/null +++ b/test/test_device_hydro_generation_constructors.jl @@ -0,0 +1,121 @@ +################################### +###### FIXED OUTPUT TESTS ######### +################################### + +@testset "Hydro DCPLossLess FixedOutput" begin + device_model = DeviceModel(HydroDispatch, FixedOutput) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 0, 0, 0, 0, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with FixedOutput formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, FixedOutput) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 0, 0, 0, 0, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +################################### +### RUN OF RIVER DISPATCH TESTS ### +################################### + +@testset "Hydro DCPLossLess HydroDispatch with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 24, 0, 48, 24, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroDispatch with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 72, 48, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 24, 0, 48, 24, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 72, 48, 0, false) + psi_checkobjfun_test(model, GAEVF) +end + +################################### +#### RUN OF RIVER COMMIT TESTS #### +################################### + +@testset "Hydro DCPLossLess HydroDispatch with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 48, 24, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroDispatch with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) + c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) + mock_construct_device!(model, device_model) + moi_tests(model, 72, 0, 72, 48, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 48, 0, 48, 24, 0, true) + psi_checkobjfun_test(model, GAEVF) +end + +@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin + device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") + + # No Parameters Testing + model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) + mock_construct_device!(model, device_model) + moi_tests(model, 72, 0, 72, 48, 0, true) + psi_checkobjfun_test(model, GAEVF) +end From a50bac5acf92ed5c88bb177198db076f3a3595c8 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 12:59:57 -0700 Subject: [PATCH 172/370] remove reservoir budget from tests --- test/test_services_constructor.jl | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index f0ba76db4a..4fd3a477a1 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -132,6 +132,29 @@ end moi_tests(model, 360, 0, 72, 48, 72, false) end +@testset "Test Reserves from Hydro" begin + template = ProblemTemplate(CopperPlatePowerModel) + set_device_model!(template, PowerLoad, StaticPowerLoad) + set_device_model!(template, HydroEnergyReservoir, HydroDispatchRunOfRiver) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve5"), + ) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveDown}, RangeReserve, "Reserve6"), + ) + set_service_model!( + template, + ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), + ) + + c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd"; add_reserves = true) + model = DecisionModel(template, c_sys5_hyd) + @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT + moi_tests(model, 240, 0, 48, 96, 72, false) +end + @testset "Test Reserves from with slack variables" begin template = get_thermal_dispatch_template_network( NetworkModel(CopperPlatePowerModel; use_slacks = true), From 022d7b4185d2998ddefe4d6f785f42fdf425ec48 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 10 May 2023 13:04:52 -0700 Subject: [PATCH 173/370] bring back hydro docs --- docs/make.jl | 1 + docs/src/formulation_library/General.md | 2 +- docs/src/formulation_library/HydroGen.md | 134 +++++++++++++++++++++++ 3 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 docs/src/formulation_library/HydroGen.md diff --git a/docs/make.jl b/docs/make.jl index 0a306e5e30..997ea23e72 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -34,6 +34,7 @@ pages = OrderedDict( "Formulation Library" => Any[ "General" => "formulation_library/General.md", "Thermal Generation" => "formulation_library/ThermalGen.md", + "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", diff --git a/docs/src/formulation_library/General.md b/docs/src/formulation_library/General.md index 0330f848f3..75ee8c70c2 100644 --- a/docs/src/formulation_library/General.md +++ b/docs/src/formulation_library/General.md @@ -29,7 +29,7 @@ using PowerSystems using DataFrames using Latexify combo_tables = [] -for t in [RenewableGen, ThermalGen, ElectricLoad] +for t in [RenewableGen, ThermalGen, HydroGen, ElectricLoad] combos = PowerSimulations.get_default_time_series_names(t, FixedOutput) combo_table = DataFrame( "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md new file mode 100644 index 0000000000..efe13982b3 --- /dev/null +++ b/docs/src/formulation_library/HydroGen.md @@ -0,0 +1,134 @@ +# `PowerSystems.HydroGen` Formulations + +Valid `DeviceModel`s for subtypes of `HydroGen` include the following: + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.generate_device_formulation_combinations() +filter!(x -> x["device_type"] <: HydroGen, combos) +combo_table = DataFrame( + "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], + "Device Type" => ["[$(c["device_type"])](https://nrel-siip.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], + "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], + ) +mdtable(combo_table, latex = false) +``` + +--- + +## `HydroDispatchRunOfRiver` + +```@docs +HydroDispatchRunOfRiver +``` + +**Variables:** + +- [`ActivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_active_power(device)` +- [`ReactivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_reactive_power(device)` + +**Static Parameters:** + +- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` +- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` +- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` + +**Time Series Parameters:** + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroDispatchRunOfRiver) +combo_table = DataFrame( + "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), + "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), + ) +mdtable(combo_table, latex = false) +``` + +**Objective:** + +Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg``. + +**Expressions:** + +Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) + +**Constraints:** + +```math +\begin{aligned} +& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ +& Qg^\text{min} \le Qg_t \le Qg^\text{max} +\end{aligned} +``` + +--- + +## `HydroCommitmentRunOfRiver` + +```@docs +HydroCommitmentRunOfRiver +``` + +**Variables:** + +- [`ActivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_active_power(device)` +- [`ReactivePowerVariable`](@ref): + - Bounds: [0.0, ] + - Default initial value: `PowerSystems.get_reactive_power(device)` +- [`OnVariable`](@ref): + - Bounds: {0, 1} + - Default initial value: `PowerSystems.get_status(device)` + +**Static Parameters:** + +- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` +- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` +- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` + +**Time Series Parameters:** + +```@eval +using PowerSimulations +using PowerSystems +using DataFrames +using Latexify +combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroCommitmentRunOfRiver) +combo_table = DataFrame( + "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), + "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), + ) +mdtable(combo_table, latex = false) +``` + +**Objective:** + +Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. + +**Expressions:** + +Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) + +**Constraints:** + +```math +\begin{aligned} +& Pg_t \le Pg^\text{max}\\ +& Pg_t - u_t Pg^\text{max} \le 0 \\ +& Pg_t - u_t Pg^\text{min} \ge 0 \\ +& Qg_t - u_t Qg^\text{max} \le 0 \\ +& Qg_t - u_t Qg^\text{min} \ge 0 +\end{aligned} +``` \ No newline at end of file From f8460a9d67cc925d81d2c6163f80c3df73eb54bb Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 7 Jul 2023 13:02:51 -0600 Subject: [PATCH 174/370] up --- Project.toml | 4 ---- README.md | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Project.toml b/Project.toml index 4374347e1c..ba7107aaa8 100644 --- a/Project.toml +++ b/Project.toml @@ -1,11 +1,7 @@ name = "PowerSimulations" uuid = "e690365d-45e2-57bb-ac84-44ba829e73c4" authors = ["Jose Daniel Lara", "Clayton Barrows", "Daniel Thom", "Dheepak Krishnamurthy", "Sourabh Dalvi"] -<<<<<<< HEAD version = "0.20.3" -======= -version = "0.20.2" ->>>>>>> bebcf0d56 (Bump version to v0.20.2) [deps] CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" diff --git a/README.md b/README.md index 0bb404163a..c73f1b1e04 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,8 @@ For example, an annual production cost modeling simulation can be created by for ```julia julia> ] -(v1.8) pkg> add PowerSystems -(v1.8) pkg> add PowerSimulations +(v1.9) pkg> add PowerSystems +(v1.9) pkg> add PowerSimulations ``` ## Usage From 16d75b2c26ab2454c102f5e5580934f26e9c0de1 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 7 Jul 2023 13:05:38 -0600 Subject: [PATCH 175/370] readme fix --- README.md | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/README.md b/README.md index c73f1b1e04..777189847b 100644 --- a/README.md +++ b/README.md @@ -54,13 +54,4 @@ Contributions to the development and enhancement of PowerSimulations is welcome. ## License -<<<<<<< HEAD -<<<<<<< HEAD -PowerSimulations is released under a BSD [license](https://github.com/NREL-Sienna/PowerSimulations.jl/blob/main/LICENSE). PowerSimulations has been developed as part of the Scalable Integrated Infrastructure Planning (SIIP) -======= -PowerSimulations is released under a BSD [license](https://github.com/NREL/PowerSimulations.jl/blob/main/LICENSE). PowerSimulations has been developed as part of the Scalable Integrated Infrastructure Planning (SIIP) ->>>>>>> 6d7e8ae80 (rename branch) -======= -PowerSimulations is released under a BSD [license](https://github.com/NREL-Sienna/PowerSimulations.jl/blob/main/LICENSE). PowerSimulations has been developed as part of the Scalable Integrated Infrastructure Planning (SIIP) ->>>>>>> 055e20d2b (more readme corrections) -initiative at the U.S. Department of Energy's National Renewable Energy Laboratory ([NREL](https://www.nrel.gov/)) +PowerSimulations is released under a BSD [license](https://github.com/NREL-Sienna/PowerSimulations.jl/blob/main/LICENSE). PowerSimulations has been developed as part of the Scalable Integrated Infrastructure Planning (SIIP) initiative at the U.S. Department of Energy's National Renewable Energy Laboratory ([NREL](https://www.nrel.gov/)) From b2ddaefab12b120e51d27dbc5531ce95a024353c Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 7 Jul 2023 13:05:54 -0600 Subject: [PATCH 176/370] fix bad merge --- docs/src/code_base_developer_guide/developer.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/src/code_base_developer_guide/developer.md b/docs/src/code_base_developer_guide/developer.md index 6650449990..b1a859819c 100644 --- a/docs/src/code_base_developer_guide/developer.md +++ b/docs/src/code_base_developer_guide/developer.md @@ -4,11 +4,7 @@ In order to contribute to `PowerSystems.jl` repository please read the following [`InfrastructureSystems.jl`](https://github.com/NREL-Sienna/InfrastructureSystems.jl) documentation in detail: -<<<<<<< HEAD 1. [Style Guide](https://nrel-Sienna.github.io/InfrastructureSystems.jl/stable/style/) -======= -1. [Style Guide](https://nrel-siip.github.io/InfrastructureSystems.jl/stable/style/) ->>>>>>> 6d7e8ae80 (rename branch) 2. [Contributing Guidelines](https://github.com/NREL-Sienna/PowerSystems.jl/blob/main/CONTRIBUTING.md) Pull requests are always welcome to fix bugs or add additional modeling capabilities. From 50eb7acf92d9d74b9d4b3264e807ac1a69c36179 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 7 Jul 2023 16:36:43 -0600 Subject: [PATCH 177/370] fix bad merge --- test/test_services_constructor.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index 4fd3a477a1..9c4100a19c 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -129,7 +129,7 @@ end c_sys5_re = PSB.build_system(PSITestSystems, "c_sys5_re"; add_reserves = true) model = DecisionModel(template, c_sys5_re) @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT - moi_tests(model, 360, 0, 72, 48, 72, false) + moi_tests(model, 360, 0, 72, 120, 72, false) end @testset "Test Reserves from Hydro" begin From 33da36173106bae047ea2cd09f8f14da61fdc4b4 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 7 Jul 2023 16:37:04 -0600 Subject: [PATCH 178/370] pin ipopt --- test/Project.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Project.toml b/test/Project.toml index efd65f0243..2ee599660f 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -32,3 +32,4 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" HiGHS = "=1.1.2" julia = "^1.6" PowerSystemCaseBuilder = "~1.0.2" +ipopt = "=1.4.0" From f707909a99b354e0479b2c65eeb8d6ceb42b93f7 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 7 Jul 2023 16:41:47 -0600 Subject: [PATCH 179/370] fix typo --- test/Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Project.toml b/test/Project.toml index 2ee599660f..72c8c475a9 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -32,4 +32,4 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" HiGHS = "=1.1.2" julia = "^1.6" PowerSystemCaseBuilder = "~1.0.2" -ipopt = "=1.4.0" +Ipopt = "=1.4.0" From 39d0f251f7b4e422dc3b032efeff5549e5cb5488 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 10 Jul 2023 17:27:17 -0600 Subject: [PATCH 180/370] create new model types --- docs/src/get_test_data.jl | 2 +- src/PowerSimulations.jl | 7 ++- src/core/optimization_container.jl | 6 ++- src/operation/decision_model.jl | 54 +++++++++++++++++--- src/operation/emulation_model.jl | 52 +++++++++++++++++-- src/operation/operation_model_interface.jl | 14 ++--- src/operation/operation_problem_templates.jl | 6 +-- src/operation/problem_template.jl | 12 +++++ test/test_utils/mock_operation_models.jl | 6 +-- 9 files changed, 126 insertions(+), 33 deletions(-) diff --git a/docs/src/get_test_data.jl b/docs/src/get_test_data.jl index 79e9e0acf3..2c99e65808 100644 --- a/docs/src/get_test_data.jl +++ b/docs/src/get_test_data.jl @@ -9,7 +9,7 @@ const PSY = PowerSystems include("../../../test/test_utils/get_test_data.jl") -abstract type TestOpProblem <: PSI.DecisionProblem end +abstract type TestOpProblem <: PSI.DefaultDecisionProblem end system = build_c_sys5_re(; add_reserves = true) solver = optimizer_with_attributes(Cbc.Optimizer) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 41a1f0c63b..5950fce00f 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -373,6 +373,7 @@ import Distributed # Base Imports import Base.getindex +import Base.isempty import Base.length import Base.first import InteractiveUtils: methodswith @@ -457,13 +458,11 @@ include("core/optimizer_stats.jl") include("core/dataset.jl") include("core/dataset_container.jl") +# Order Required +include("operation/problem_template.jl") include("core/optimization_container.jl") include("core/store_common.jl") - -# Order Required include("initial_conditions/initial_condition_chronologies.jl") - -include("operation/problem_template.jl") include("operation/operation_model_interface.jl") include("operation/model_store_params.jl") include("operation/abstract_model_store.jl") diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index 08130009f5..2bd9e798bf 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -475,7 +475,11 @@ function initialize_system_expressions!( return end -function build_impl!(container::OptimizationContainer, template, sys::PSY.System) +function build_impl!( + container::OptimizationContainer, + template::ProblemTemplate, + sys::PSY.System, +) transmission = get_network_formulation(template) transmission_model = get_network_model(template) initialize_system_expressions!(container, transmission, transmission_model.subnetworks) diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index cd0fa9d1e3..0bc9887a03 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -1,7 +1,13 @@ """ -Default PowerSimulations Operation Problem Type +Abstract type for models than employ PowerSimulations methods. For custom decision problems + use DecisionProblem as the super type. """ -struct GenericOpProblem <: DecisionProblem end +abstract type DefaultDecisionProblem <: DecisionProblem end + +""" +Generic PowerSimulations Operation Problem Type for unspecified models +""" +struct GenericOpProblem <: DefaultDecisionProblem end """ DecisionModel{M}( @@ -10,7 +16,7 @@ struct GenericOpProblem <: DecisionProblem end jump_model::Union{Nothing, JuMP.Model}=nothing; kwargs...) where {M<:DecisionProblem} -This builds the optimization problem of type M with the specific system and template. +Builds the optimization problem of type M with the specific system and template. # Arguments @@ -135,7 +141,7 @@ function DecisionModel{M}( end """ -This builds the optimization problem of type M with the specific system and template +Builds the optimization problem of type M with the specific system and template # Arguments @@ -170,6 +176,30 @@ function DecisionModel( return DecisionModel{GenericOpProblem}(template, sys, jump_model; kwargs...) end +""" +Builds an empty decision model. This constructor is used for the implementation of custom +decision models that do not require a template. + +# Arguments + + - `::Type{M} where M<:DecisionProblem`: The abstract operation model type + - `sys::PSY.System`: 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 = DecisionModel(system, optimizer) +``` +""" +function DecisionModel{M}( + sys::PSY.System, + jump_model::Union{Nothing, JuMP.Model} = nothing; + kwargs..., +) where {M <: DecisionProblem} + return DecisionModel{M}(ProblemTemplate(), sys, jump_model; kwargs...) +end + """ Construct an DecisionProblem from a serialized file. @@ -199,6 +229,9 @@ function DecisionModel( ) end +get_problem_type(::DecisionModel{M}) where {M <: DecisionProblem} = M +validate_template(::DecisionModel{<:DecisionProblem}) = nothing + # Probably could be more efficient by storing the info in the internal function get_current_time(model::DecisionModel) execution_count = get_internal(model).execution_count @@ -227,9 +260,9 @@ function init_model_store_params!(model::DecisionModel) return end -function build_pre_step!(model::DecisionModel) +function build_pre_step!(model::DecisionModel{<:DefaultDecisionProblem}) TimerOutputs.@timeit BUILD_PROBLEMS_TIMER "Build pre-step" begin - if !is_empty(model) + if !isempty(model) @info "OptimizationProblem status not BuildStatus.EMPTY. Resetting" reset!(model) end @@ -253,6 +286,15 @@ function build_pre_step!(model::DecisionModel) return end +function build_impl!(model::DecisionModel{<:DefaultDecisionProblem}) + validate_template(model) + build_pre_step!(model) + build_model!(model) + serialize_metadata!(get_optimization_container(model), get_output_dir(model)) + log_values(get_settings(model)) + return +end + get_horizon(model::DecisionModel) = get_horizon(get_settings(model)) """ diff --git a/src/operation/emulation_model.jl b/src/operation/emulation_model.jl index 0a18b644d1..b683db2f26 100644 --- a/src/operation/emulation_model.jl +++ b/src/operation/emulation_model.jl @@ -1,7 +1,13 @@ """ -Default PowerSimulations Emulation Problem Type +Abstract type for models than employ PowerSimulations methods. For custom emulation problems + use EmulationProblem as the super type. """ -struct GenericEmulationProblem <: EmulationProblem end +abstract type DefaultEmulationProblem <: EmulationProblem end + +""" +Default PowerSimulations Emulation Problem Type for unspecified problems +""" +struct GenericEmulationProblem <: DefaultEmulationProblem end """ EmulationModel{M}( @@ -10,7 +16,7 @@ struct GenericEmulationProblem <: EmulationProblem end jump_model::Union{Nothing, JuMP.Model}=nothing; kwargs...) where {M<:EmulationProblem} -This builds the optimization problem of type M with the specific system and template. +Builds the optimization problem of type M with the specific system and template. # Arguments @@ -126,7 +132,7 @@ function EmulationModel{M}( end """ -This builds the optimization problem of type M with the specific system and template +Builds the optimization problem of type M with the specific system and template # Arguments @@ -162,6 +168,30 @@ function EmulationModel( 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::PSY.System`: 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::PSY.System, + jump_model::Union{Nothing, JuMP.Model} = nothing; + kwargs..., +) where {M <: EmulationProblem} + return EmulationModel{M}(template, sys, jump_model; kwargs...) +end + """ Construct an EmulationProblem from a serialized file. @@ -192,6 +222,9 @@ function EmulationModel( ) end +get_problem_type(::EmulationModel{M}) where {M <: EmulationProblem} = M +validate_template(::EmulationModel{<:EmulationProblem}) = nothing + function get_current_time(model::EmulationModel) execution_count = get_internal(model).execution_count initial_time = get_initial_time(model) @@ -219,7 +252,7 @@ end function build_pre_step!(model::EmulationModel) TimerOutputs.@timeit BUILD_PROBLEMS_TIMER "Build pre-step" begin - if !is_empty(model) + if !isempty(model) @info "EmulationProblem status not BuildStatus.EMPTY. Resetting" reset!(model) end @@ -243,6 +276,15 @@ function build_pre_step!(model::EmulationModel) return end +function build_impl!(model::EmulationModel{<:DefaultEmulationProblem}) + validate_template(model) + build_pre_step!(model) + build_model!(model) + serialize_metadata!(get_optimization_container(model), get_output_dir(model)) + log_values(get_settings(model)) + return +end + """ Implementation of build for any EmulationProblem """ diff --git a/src/operation/operation_model_interface.jl b/src/operation/operation_model_interface.jl index ecd0b99d7a..8bdf36a6e0 100644 --- a/src/operation/operation_model_interface.jl +++ b/src/operation/operation_model_interface.jl @@ -1,6 +1,6 @@ # Default implementations of getter/setter functions for OperationModel. is_built(model::OperationModel) = model.internal.status == BuildStatus.BUILT -is_empty(model::OperationModel) = model.internal.status == BuildStatus.EMPTY +isempty(model::OperationModel) = model.internal.status == BuildStatus.EMPTY warm_start_enabled(model::OperationModel) = get_warm_start(get_optimization_container(model).settings) built_for_recurrent_solves(model::OperationModel) = @@ -213,6 +213,9 @@ end function validate_template(model::OperationModel) template = get_template(model) + if isempty(template) + error("Template can't be empty for models $(get_problem_type(model))") + end modeled_types = get_component_types(template) system = get_system(model) system_component_types = PSY.get_existing_component_types(system) @@ -228,15 +231,6 @@ function validate_template(model::OperationModel) return end -function build_impl!(model::OperationModel) - validate_template(model) - build_pre_step!(model) - build_model!(model) - serialize_metadata!(get_optimization_container(model), get_output_dir(model)) - log_values(get_settings(model)) - return -end - function build_if_not_already_built!(model; kwargs...) status = get_status(model) if status == BuildStatus.EMPTY diff --git a/src/operation/operation_problem_templates.jl b/src/operation/operation_problem_templates.jl index 5a60c03c52..fb6a1f9206 100644 --- a/src/operation/operation_problem_templates.jl +++ b/src/operation/operation_problem_templates.jl @@ -1,7 +1,7 @@ -struct EconomicDispatchProblem <: DecisionProblem end -struct UnitCommitmentProblem <: DecisionProblem end -struct AGCReserveDeployment <: DecisionProblem end +struct EconomicDispatchProblem <: DefaultDecisionProblem end +struct UnitCommitmentProblem <: DefaultDecisionProblem end +struct AGCReserveDeployment <: DefaultDecisionProblem end function _default_devices_uc() return [ diff --git a/src/operation/problem_template.jl b/src/operation/problem_template.jl index 5e39f69525..ab2a5c785e 100644 --- a/src/operation/problem_template.jl +++ b/src/operation/problem_template.jl @@ -31,6 +31,18 @@ mutable struct ProblemTemplate end end +function Base.isempty(template::ProblemTemplate) + if !isempty(template.devices) + return false + elseif !isempty(template.branches) + return false + elseif !isempty(template.services) + return false + else + return true + end +end + ProblemTemplate(::Type{T}) where {T <: PM.AbstractPowerModel} = ProblemTemplate(NetworkModel(T)) ProblemTemplate() = ProblemTemplate(CopperPlatePowerModel) diff --git a/test/test_utils/mock_operation_models.jl b/test/test_utils/mock_operation_models.jl index 4f00ac010f..49b276d237 100644 --- a/test/test_utils/mock_operation_models.jl +++ b/test/test_utils/mock_operation_models.jl @@ -1,8 +1,8 @@ # NOTE: None of the models and function in this file are functional. All of these are used for testing purposes and do not represent valid examples either to develop custom # models. Please refer to the documentation. -struct MockOperationProblem <: PSI.DecisionProblem end -struct MockEmulationProblem <: PSI.EmulationProblem end +struct MockOperationProblem <: PSI.DefaultDecisionProblem end +struct MockEmulationProblem <: PSI.DefaultEmulationProblem end function PSI.DecisionModel( ::Type{MockOperationProblem}, @@ -194,7 +194,7 @@ end function setup_ic_model_container!(model::DecisionModel) # This function is only for testing purposes. - if !PSI.is_empty(model) + if !PSI.isempty(model) PSI.reset!(model) end From ce91bbae782966e5e76c4a5ab3be1e1e4ee47f31 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 10 Jul 2023 20:47:28 -0600 Subject: [PATCH 181/370] additional updates to build custom models --- src/operation/decision_model.jl | 47 ++++++++----- src/operation/decision_model_store.jl | 4 ++ src/operation/emulation_model.jl | 29 +++++--- src/operation/operation_model_interface.jl | 79 ++++++++++++---------- 4 files changed, 95 insertions(+), 64 deletions(-) diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index 0bc9887a03..bd66362618 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -71,12 +71,6 @@ mutable struct DecisionModel{M <: DecisionProblem} <: OperationModel elseif name isa String name = Symbol(name) end - _, _, forecast_count = PSY.get_time_series_counts(sys) - if forecast_count < 1 - error( - "The system does not contain forecast data. A DecisionModel can't be built.", - ) - end internal = ModelInternal( OptimizationContainer(sys, settings, jump_model, PSY.Deterministic), ) @@ -200,6 +194,16 @@ function DecisionModel{M}( return DecisionModel{M}(ProblemTemplate(), sys, jump_model; kwargs...) end +function DecisionModel{M}( + sys::PSY.System, + jump_model::Union{Nothing, JuMP.Model} = nothing; + kwargs..., +) where {M <: DefaultDecisionProblem} + IS.ArgumentError( + "DefaultDecisionProblem subtypes require a template. Use DecisionModel subtyping instead.", + ) +end + """ Construct an DecisionProblem from a serialized file. @@ -231,6 +235,7 @@ end get_problem_type(::DecisionModel{M}) where {M <: DecisionProblem} = M validate_template(::DecisionModel{<:DecisionProblem}) = nothing +validate_time_series(::DecisionModel{<:DecisionProblem}) = nothing # Probably could be more efficient by storing the info in the internal function get_current_time(model::DecisionModel) @@ -260,35 +265,45 @@ function init_model_store_params!(model::DecisionModel) return end -function build_pre_step!(model::DecisionModel{<:DefaultDecisionProblem}) +function validate_time_series(model::DecisionModel{<:DefaultDecisionProblem}) + sys = get_system(model) + _, _, forecast_count = PSY.get_time_series_counts(sys) + if forecast_count < 1 + error( + "The system does not contain forecast data. A DecisionModel can't be built.", + ) + end + return +end + +function build_pre_step!(model::DecisionModel{<:DecisionProblem}) TimerOutputs.@timeit BUILD_PROBLEMS_TIMER "Build pre-step" begin + validate_template(model) + validate_time_series(model) if !isempty(model) @info "OptimizationProblem status not BuildStatus.EMPTY. Resetting" reset!(model) end # Initial time are set here because the information is specified in the # Simulation Sequence object and not at the problem creation. - @info "Initializing Optimization Container For a DecisionModel" init_optimization_container!( get_optimization_container(model), get_network_formulation(get_template(model)), get_system(model), ) - @info "Instantiating Network Model" - instantiate_network_model(model) @info "Initializing ModelStoreParams" init_model_store_params!(model) - - handle_initial_conditions!(model) set_status!(model, BuildStatus.IN_PROGRESS) end return end -function build_impl!(model::DecisionModel{<:DefaultDecisionProblem}) - validate_template(model) +function build_impl!(model::DecisionModel{<:DecisionProblem}) build_pre_step!(model) + @info "Instantiating Network Model" + instantiate_network_model(model) + handle_initial_conditions!(model) build_model!(model) serialize_metadata!(get_optimization_container(model), get_output_dir(model)) log_values(get_settings(model)) @@ -352,12 +367,12 @@ end Default implementation of build method for Operational Problems for models conforming with DecisionProblem specification. Overload this function to implement a custom build method """ -function build_model!(model::DecisionModel) +function build_model!(model::DecisionModel{<:DefaultDecisionProblem}) build_impl!(get_optimization_container(model), get_template(model), get_system(model)) return end -function reset!(model::DecisionModel) +function reset!(model::DecisionModel{<:DefaultDecisionProblem}) was_built_for_recurrent_solves = built_for_recurrent_solves(model) if was_built_for_recurrent_solves set_execution_count!(model, 0) diff --git a/src/operation/decision_model_store.jl b/src/operation/decision_model_store.jl index 30efdf3c84..24f10bbfcf 100644 --- a/src/operation/decision_model_store.jl +++ b/src/operation/decision_model_store.jl @@ -42,6 +42,9 @@ function initialize_storage!( params::ModelStoreParams, ) num_of_executions = get_num_executions(params) + if length(get_time_steps(container)) < 1 + error("The time step count in the optimization container is not defined") + end time_steps_count = get_time_steps(container)[end] initial_time = get_initial_time(container) model_interval = get_interval(params) @@ -62,6 +65,7 @@ function initialize_storage!( end end end + return end function write_result!( diff --git a/src/operation/emulation_model.jl b/src/operation/emulation_model.jl index b683db2f26..e6193b52a1 100644 --- a/src/operation/emulation_model.jl +++ b/src/operation/emulation_model.jl @@ -70,12 +70,6 @@ mutable struct EmulationModel{M <: EmulationProblem} <: OperationModel elseif name isa String name = Symbol(name) end - _, ts_count, _ = PSY.get_time_series_counts(sys) - if ts_count < 1 - error( - "The system does not contain Static TimeSeries data. An Emulation model can't be formulated.", - ) - end finalize_template!(template, sys) internal = ModelInternal( OptimizationContainer(sys, settings, jump_model, PSY.SingleTimeSeries), @@ -224,6 +218,7 @@ end get_problem_type(::EmulationModel{M}) where {M <: EmulationProblem} = M validate_template(::EmulationModel{<:EmulationProblem}) = nothing +validate_time_series(::EmulationModel{<:EmulationProblem}) = nothing function get_current_time(model::EmulationModel) execution_count = get_internal(model).execution_count @@ -250,8 +245,21 @@ function init_model_store_params!(model::EmulationModel) return end +function validate_time_series(model::EmulationModel{<:DefaultEmulationProblem}) + sys = get_system(model) + _, ts_count, _ = PSY.get_time_series_counts(sys) + if ts_count < 1 + error( + "The system does not contain Static TimeSeries data. An Emulation model can't be formulated.", + ) + end + return +end + function build_pre_step!(model::EmulationModel) TimerOutputs.@timeit BUILD_PROBLEMS_TIMER "Build pre-step" begin + validate_template(model) + validate_time_series(model) if !isempty(model) @info "EmulationProblem status not BuildStatus.EMPTY. Resetting" reset!(model) @@ -265,20 +273,19 @@ function build_pre_step!(model::EmulationModel) get_network_formulation(get_template(model)), get_system(model), ) - @info "Instantiating Network Model" - instantiate_network_model(model) @info "Initializing ModelStoreParams" init_model_store_params!(model) - handle_initial_conditions!(model) set_status!(model, BuildStatus.IN_PROGRESS) end return end -function build_impl!(model::EmulationModel{<:DefaultEmulationProblem}) - validate_template(model) +function build_impl!(model::EmulationModel{<:EmulationProblem}) build_pre_step!(model) + @info "Instantiating Network Model" + instantiate_network_model(model) + handle_initial_conditions!(model) build_model!(model) serialize_metadata!(get_optimization_container(model), get_output_dir(model)) log_values(get_settings(model)) diff --git a/src/operation/operation_model_interface.jl b/src/operation/operation_model_interface.jl index 8bdf36a6e0..6e0eb8eb86 100644 --- a/src/operation/operation_model_interface.jl +++ b/src/operation/operation_model_interface.jl @@ -144,48 +144,53 @@ function write_initial_conditions_data!(model::OperationModel) end function handle_initial_conditions!(model::OperationModel) - settings = get_settings(model) - initialize_model = get_initialize_model(settings) - deserialize_initial_conditions = get_deserialize_initial_conditions(settings) - serialized_initial_conditions_file = get_initial_conditions_file(model) - custom_init_file = get_initialization_file(settings) - - if !initialize_model && deserialize_initial_conditions - throw( - IS.ConflictingInputsError( - "!initialize_model && deserialize_initial_conditions", - ), - ) - elseif !initialize_model && !isempty(custom_init_file) - throw(IS.ConflictingInputsError("!initialize_model && initialization_file")) - end - - if !initialize_model - @info "Skip build of initial conditions" - return - end + TimerOutputs.@timeit BUILD_PROBLEMS_TIMER "Model Initialization" begin + if isempty(get_template(model)) + return + end + settings = get_settings(model) + initialize_model = get_initialize_model(settings) + deserialize_initial_conditions = get_deserialize_initial_conditions(settings) + serialized_initial_conditions_file = get_initial_conditions_file(model) + custom_init_file = get_initialization_file(settings) + + if !initialize_model && deserialize_initial_conditions + throw( + IS.ConflictingInputsError( + "!initialize_model && deserialize_initial_conditions", + ), + ) + elseif !initialize_model && !isempty(custom_init_file) + throw(IS.ConflictingInputsError("!initialize_model && initialization_file")) + end - if !isempty(custom_init_file) - if !isfile(custom_init_file) - error("initialization_file = $custom_init_file does not exist") + if !initialize_model + @info "Skip build of initial conditions" + return end - if abspath(custom_init_file) != abspath(serialized_initial_conditions_file) - cp(custom_init_file, serialized_initial_conditions_file; force = true) + + if !isempty(custom_init_file) + if !isfile(custom_init_file) + error("initialization_file = $custom_init_file does not exist") + end + if abspath(custom_init_file) != abspath(serialized_initial_conditions_file) + cp(custom_init_file, serialized_initial_conditions_file; force = true) + end end - end - if deserialize_initial_conditions && isfile(serialized_initial_conditions_file) - set_initial_conditions_data!( - model.internal.container, - Serialization.deserialize(serialized_initial_conditions_file), - ) - @info "Deserialized initial_conditions_data" - else - @info "Make Initial Conditions Model" - build_initial_conditions!(model) - initialize!(model) + if deserialize_initial_conditions && isfile(serialized_initial_conditions_file) + set_initial_conditions_data!( + model.internal.container, + Serialization.deserialize(serialized_initial_conditions_file), + ) + @info "Deserialized initial_conditions_data" + else + @info "Make Initial Conditions Model" + build_initial_conditions!(model) + initialize!(model) + end + model.internal.ic_model_container = nothing end - model.internal.ic_model_container = nothing return end From b713cefc94bb6041da706469f9a08de9eaf07977 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 10:12:55 -0600 Subject: [PATCH 182/370] improvements to objective function --- src/core/optimization_container.jl | 34 ++++++++++++++++-------- src/operation/decision_model.jl | 2 +- src/operation/emulation_model.jl | 2 +- test/test_utils/mock_operation_models.jl | 2 +- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index 2bd9e798bf..9501b9c5d8 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -54,15 +54,30 @@ mutable struct ObjectiveFunction invariant_terms::JuMP.AbstractJuMPScalar variant_terms::GAE synchronized::Bool + sense::MOI.OptimizationSense + function ObjectiveFunction(invariant_terms::JuMP.AbstractJuMPScalar, + variant_terms::GAE, + synchronized::Bool, + sense::MOI.OptimizationSense = MOI.MIN_SENSE) + new(invariant_terms, variant_terms, synchronized, sense) + end end get_invariant_terms(v::ObjectiveFunction) = v.invariant_terms get_variant_terms(v::ObjectiveFunction) = v.variant_terms -get_objective_function(v::ObjectiveFunction) = v.variant_terms + v.invariant_terms +function get_objective_expression(v::ObjectiveFunction) + if iszero(v.variant_terms) + return v.invariant_terms + else + return JuMP.add_to_expression!(v.variant_terms, v.invariant_terms) + end +end +get_sense(v::ObjectiveFunction) = v.sense is_synchronized(v::ObjectiveFunction) = v.synchronized set_synchronized_status(v::ObjectiveFunction, value) = v.synchronized = value reset_variant_terms(v::ObjectiveFunction) = v.variant_terms = zero(JuMP.AffExpr) has_variant_terms(v::ObjectiveFunction) = !iszero(v.variant_terms) +set_sense!(v::ObjectiveFunction, sense::MOI.OptimizationSense) = v.sense = sense function ObjectiveFunction() return ObjectiveFunction( @@ -150,7 +165,7 @@ get_base_power(container::OptimizationContainer) = container.base_power get_constraints(container::OptimizationContainer) = container.constraints function cost_function_unsynch(container::OptimizationContainer) - obj_func = PSI.get_objective_function(container) + obj_func = PSI.get_objective_expression(container) if has_variant_terms(obj_func) && PSI.is_synchronized(container) PSI.set_synchronized_status(obj_func, false) PSI.reset_variant_terms(obj_func) @@ -183,9 +198,10 @@ get_variables(container::OptimizationContainer) = container.variables set_initial_conditions_data!(container::OptimizationContainer, data) = container.initial_conditions_data = data -get_objective_function(container::OptimizationContainer) = container.objective_function +get_objective_expression(container::OptimizationContainer) = container.objective_function is_synchronized(container::OptimizationContainer) = container.objective_function.synchronized +set_time_steps!(container::OptimizationContainer, time_steps::UnitRange{Int64}) = container.time_steps = time_steps function has_container_key( container::OptimizationContainer, @@ -588,11 +604,7 @@ function build_impl!( TimerOutputs.@timeit BUILD_PROBLEMS_TIMER "Objective" begin @debug "Building Objective" _group = LOG_GROUP_OPTIMIZATION_CONTAINER - JuMP.@objective( - container.JuMPmodel, - MOI.MIN_SENSE, - get_objective_function(container.objective_function) - ) + update_objective_function!(container) end @debug "Total operation count $(container.JuMPmodel.operator_counter)" _group = LOG_GROUP_OPTIMIZATION_CONTAINER @@ -604,9 +616,9 @@ end function update_objective_function!(container::OptimizationContainer) JuMP.@objective( - container.JuMPmodel, - MOI.MIN_SENSE, - get_objective_function(container.objective_function) + get_jump_model(container), + get_sense(container.objective_function), + get_objective_expression(container.objective_function) ) return end diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index bd66362618..b9beae7182 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -527,7 +527,7 @@ function update_parameters!( end if !is_synchronized(model) update_objective_function!(get_optimization_container(model)) - obj_func = get_objective_function(get_optimization_container(model)) + obj_func = get_objective_expression(get_optimization_container(model)) set_synchronized_status(obj_func, true) end return diff --git a/src/operation/emulation_model.jl b/src/operation/emulation_model.jl index e6193b52a1..7f8a21a0f4 100644 --- a/src/operation/emulation_model.jl +++ b/src/operation/emulation_model.jl @@ -375,7 +375,7 @@ function update_parameters!(model::EmulationModel, data::DatasetContainer{DataFr end if !is_synchronized(model) update_objective_function!(get_optimization_container(model)) - obj_func = get_objective_function(get_optimization_container(model)) + obj_func = get_objective_expression(get_optimization_container(model)) set_synchronized_status(obj_func, true) end return diff --git a/test/test_utils/mock_operation_models.jl b/test/test_utils/mock_operation_models.jl index 49b276d237..f1166c01cb 100644 --- a/test/test_utils/mock_operation_models.jl +++ b/test/test_utils/mock_operation_models.jl @@ -139,7 +139,7 @@ function mock_construct_device!( JuMP.@objective( PSI.get_jump_model(problem), MOI.MIN_SENSE, - PSI.get_objective_function( + PSI.get_objective_expression( PSI.get_optimization_container(problem).objective_function, ) ) From e74434f76056f3bc3d254e64a0fc76e1bb2100ea Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 12:26:30 -0600 Subject: [PATCH 183/370] improve docs pages --- .../adding_new_problem_model.md | 6 -- .../structure_of_operation_problem.md | 10 +++ docs/src/modeler_guide/definitions.md | 6 +- .../adding_new_device_formulation.md | 0 .../src/tutorials/adding_new_problem_model.md | 85 +++++++++++++++++++ .../tutorials/basics_of_developing_models.md | 3 + 6 files changed, 101 insertions(+), 9 deletions(-) delete mode 100644 docs/src/model_developer_guide/adding_new_problem_model.md create mode 100644 docs/src/model_developer_guide/structure_of_operation_problem.md rename docs/src/{model_developer_guide => tutorials}/adding_new_device_formulation.md (100%) create mode 100644 docs/src/tutorials/adding_new_problem_model.md create mode 100644 docs/src/tutorials/basics_of_developing_models.md diff --git a/docs/src/model_developer_guide/adding_new_problem_model.md b/docs/src/model_developer_guide/adding_new_problem_model.md deleted file mode 100644 index 9083c2309c..0000000000 --- a/docs/src/model_developer_guide/adding_new_problem_model.md +++ /dev/null @@ -1,6 +0,0 @@ -# Adding an Operations Problem Model - -## Decision Problem - - -## Emulation Problem diff --git a/docs/src/model_developer_guide/structure_of_operation_problem.md b/docs/src/model_developer_guide/structure_of_operation_problem.md new file mode 100644 index 0000000000..b4d67b51d0 --- /dev/null +++ b/docs/src/model_developer_guide/structure_of_operation_problem.md @@ -0,0 +1,10 @@ +# Structure of an operations problem model + +In most cases operation problem models are optimization models. Although in `PowerSimulations.jl` it is +possible to define arbitrary problems that can reflect heuristic decision rules, this is not the common case. This page focuses on explaining the structure of operations problems that employ and optimization problem and solver. + +The first aspect to consider when thinking about developing a model compatible with `PowerSimulations.jl` is that although we support all of `JuMP.jl` objects, you need to employ [anonymous constraints and variables in JuMP](https://jump.dev/JuMP.jl/stable/manual/variables/#anonymous_variables) +and register the constraints, variables and other optimization objects into PowerSimulations.jl's optimization container. Otherwise the features to use your problem in the simulation like the coordination with other problems and post processing won't work. + +!!! info + The requirements for the simulation of Power Systems operations are more strict than solving an optimization problem once with just `JuMP.jl`. The requirements imposed by `PowerSimulations.jl` to integrate your models in a simulation are designed to help with other complex operations that go beyond `JuMP.jl` scope. diff --git a/docs/src/modeler_guide/definitions.md b/docs/src/modeler_guide/definitions.md index cc42de6e72..77a91065e0 100644 --- a/docs/src/modeler_guide/definitions.md +++ b/docs/src/modeler_guide/definitions.md @@ -10,12 +10,12 @@ ## H -* *Horizon*: The number of steps in the look-ahead of a decision problem. For instance, a Day-ahead problem usually has a 48 step horizon. +* *Horizon*: The number of steps in the look-ahead of a decision problem. For instance, a Day-Ahead problem usually has a 48 step horizon. Check the time [Time Series Data Section in PowerSystems.jl](https://nrel-sienna.github.io/PowerSystems.jl/stable/modeler_guide/time_series/) ## I -* *Interval*: +* *Interval*: The amount of time between updates to the decision problem. For instance, Day-Ahead problems usually have a 24-hour intervals and Real-Time problems have 5-minute intervals. Check the time [Time Series Data Section in PowerSystems.jl](https://nrel-sienna.github.io/PowerSystems.jl/stable/modeler_guide/time_series/) ## R -* *Resolution*: The amount of time between timesteps in a simulation. For instance 1-hour or 5-minutes. In Julia these are defined using the syntax `Hour(1)` and `Minute(5)` +* *Resolution*: The amount of time between timesteps in a simulation. For instance 1-hour or 5-minutes. In Julia these are defined using the syntax `Hour(1)` and `Minute(5)`. Check the time [Time Series Data Section in PowerSystems.jl](https://nrel-sienna.github.io/PowerSystems.jl/stable/modeler_guide/time_series/) diff --git a/docs/src/model_developer_guide/adding_new_device_formulation.md b/docs/src/tutorials/adding_new_device_formulation.md similarity index 100% rename from docs/src/model_developer_guide/adding_new_device_formulation.md rename to docs/src/tutorials/adding_new_device_formulation.md diff --git a/docs/src/tutorials/adding_new_problem_model.md b/docs/src/tutorials/adding_new_problem_model.md new file mode 100644 index 0000000000..0134dd58b4 --- /dev/null +++ b/docs/src/tutorials/adding_new_problem_model.md @@ -0,0 +1,85 @@ +# Adding an Operations Problem Model + +This tutorial will show how to create a custom decision problem model. These cases are the ones +where the user want to solve a fully specified problem. Some examples of custom decision models include: + +- Solving a custom Security Constrained Unit Commitment Problem +- Solving a market agent utility maximization Problem. See examples of this functionality in HybridSystemsSimulations.jl + +The tutorial follows the usual steps for operational model building. First, build the decision model in isolation and second integrate int a simulation. In most cases there will be more than one way of achieving +the same objective when it comes to implementing the model. This guide shows a general set of steps and requirements but it is by no means an exhaustive and detailed guide on developing custom decision models. + +!!! warning + All the code in this tutorial is considered "pseudo-code". If you copy-paste will likely not work out of the box. You need to develop the internals of the functions correctly for the examples below to work. + +## General Rules + +1. As a general rule you need to understand Julia's terminology such as multiple dispatch, parametried structs and method overloading among others. Developing custom models for an operational simulation is highly technical task and requires skilled development. This tuturial also requires good understanding of PowerSystems.jl data structures and features which are covered in the tutorials section of PowerSystems.jl documentation. +Finally, developing a custom model decision model that will employ an optimization model under the hood requires understanding JuMP.jl. + +2. Need to employ [anonymous constraints and variables in JuMP](https://jump.dev/JuMP.jl/stable/manual/variables/#anonymous_variables) +and register the constraints, variables and other optimization objects into PowerSimulations.jl's optimization container. Otherwise the +features to use your problem in the simulation like the coordination with other problems and post processing won't work. More on this in the section [How to develop your `build_model!` function](@ref) below. + +3. Overload the required methods for your custom decision models. In some cases it will be possible to re-use some of the other methods that exist in PowerSimulations to make life easier for variable addition and constraint creation but this is not required. + +## Decision Problem + +### Step 1: Define a Custom Decision Problem + +Define a decision problem struct as a subtype of `PowerSimulations.DecisionProblem`. This requirement will enable a lot of the underlying functionality that relies on multiple dispatch. DecisionProblems are used to parameterize the behavior of `DecisionModel` objects which are just containers +for the parameters, references and the optimization problem. + +It is possible to define a Custom Decision Problem that gives the user full control over the build, solve and execution process since it imposes less requirements on the developer. However, with less requirements there are also less check and validations performed inside of PowerSimulations which might lead to unexpected erros. + +```julia +struct MyCustomDecisionProblem <: PSI.DecisionProblem end +``` + +Alternatevely, it is possible to define a Custom Decision Problem subtyping from `DefaultDecisionProblem` which imposes more requirements and structure onto the developer but employs more checks and validations in the process. Be aware that this route will decrease the flexibility of what can be done inside the custom model. + +```julia +struct MyCustomDecisionProblem <: PSI.DefaultDecisionProblem end +``` + +Once the problem type is defined, initialize the decision model container with your custom decision problem passing the solver and some of the settings you need for the solution of the problem. For custom problems some of the settings need manual implementation by the developer. Settings availability is also dependent on wether you choose to subtype from `PSI.DecisionProblem` or `PSI.DefaultDecisionProblem` + +```julia +my_model = DecisionModel{MyCustomDecisionProblem}( + sys; + name = "MyModel", + optimizer = optimizer_with_attributes(HiGHS.Optimizer), + optimizer_solve_log_print = true, +) +``` + +#### Mandatory Method Overloads + +1. `build_model!`: This method build the `JuMP` optimization model. + +#### Optional Method Overloads + +These methods can be defined optionally for your problem. By default for problems subtyped from `DecisionProblem` these checks are not executed. If the problems are subtyped from `DefaultDecisionProblem` these checks are always conducted with PowerSimulations defaults and require compliance with those defaults to pass. In any case, these can be overloaded when necessary depending on the problem requirements. + +1. `validate_template` +2. `validate_time_series` +3. `reset!` +4. `solve_impl!` + +### How to develop your `build_model!` function + + + +```julia +function PSI.build_model!(model::PSI.DecisionModel{MyCustomDecisionProblem}) + container = PSI.get_optimization_container(model) + PSI.set_time_steps!(container, 1:24) # <- Mandatory + system = PSI.get_system(model) + + + + update_objective_function!(container) # <- Mandatory +end +``` + +## Emulation Problem diff --git a/docs/src/tutorials/basics_of_developing_models.md b/docs/src/tutorials/basics_of_developing_models.md new file mode 100644 index 0000000000..a027918d6a --- /dev/null +++ b/docs/src/tutorials/basics_of_developing_models.md @@ -0,0 +1,3 @@ +# Basics of Developing Operation Models + +Check the page [PowerSimulations Structure](@ref) for more background on PowerSimulations.jl From 5dd61df27c9da90666604c3f2d49b28c1483b0b3 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 14:23:23 -0600 Subject: [PATCH 184/370] formatter --- src/core/optimization_container.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index 9501b9c5d8..361f525670 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -201,7 +201,8 @@ set_initial_conditions_data!(container::OptimizationContainer, data) = get_objective_expression(container::OptimizationContainer) = container.objective_function is_synchronized(container::OptimizationContainer) = container.objective_function.synchronized -set_time_steps!(container::OptimizationContainer, time_steps::UnitRange{Int64}) = container.time_steps = time_steps +set_time_steps!(container::OptimizationContainer, time_steps::UnitRange{Int64}) = + container.time_steps = time_steps function has_container_key( container::OptimizationContainer, From 496483b7352e5add8d6033ba50cb64178940c4a1 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 15:51:34 -0600 Subject: [PATCH 185/370] remove more hybrid --- docs/src/api/PowerSimulations.md | 30 --------- src/PowerSimulations.jl | 12 ---- src/core/constraints.jl | 7 -- src/core/variables.jl | 40 ----------- .../devices/common/objective_functions.jl | 23 ------- .../devices/hydro_generation.jl | 4 -- src/feedforward/feedforward_arguments.jl | 13 ---- src/feedforward/feedforward_constraints.jl | 67 ------------------- 8 files changed, 196 deletions(-) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index 2c935b8d8b..f4ead20864 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -130,24 +130,6 @@ PowerAboveMinimumVariable ReservationVariable ``` -### Hydro Variables - -```@docs -WaterSpillageVariable -EnergyVariableUp -EnergyVariableDown -``` - -### Common for Hydro and Storage Variables - -```@docs -ActivePowerOutVariable -ActivePowerInVariable -EnergyVariable -EnergyShortageVariable -EnergySurplusVariable -``` - ### Branches and Network Variables ```@docs @@ -247,18 +229,6 @@ EqualityConstraint ``` -### Hydro and Storage Constraints - -```@docs -EnergyBalanceConstraint -EnergyBudgetConstraint -EnergyCapacityConstraint -EnergyCapacityDownConstraint -EnergyCapacityUpConstraint -EnergyTargetConstraint -RangeLimitConstraint -``` - ### Branches Constraints ```@docs diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 5950fce00f..68a74a029f 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -204,17 +204,12 @@ export HotStartVariable export WarmStartVariable export ColdStartVariable export EnergyVariable -export EnergyVariableUp -export EnergyVariableDown -export EnergyShortageVariable -export EnergySurplusVariable export LiftVariable export OnVariable export ReactivePowerVariable export ReservationVariable export ActivePowerReserveVariable export ServiceRequirementVariable -export WaterSpillageVariable export StartVariable export StopVariable export SteadyStateFrequencyDeviation @@ -256,13 +251,6 @@ export CommitmentConstraint export CopperPlateBalanceConstraint export DurationConstraint export EnergyBalanceConstraint -export EnergyBudgetConstraint -export EnergyCapacityConstraint -export EnergyCapacityDownConstraint -export EnergyCapacityUpConstraint -export EnergyLimitConstraint -export EnergyShortageVariableLimitsConstraint -export EnergyTargetConstraint export EqualityConstraint export FeedforwardSemiContinousConstraint export FeedforwardUpperBoundConstraint diff --git a/src/core/constraints.jl b/src/core/constraints.jl index 79da9e177c..f64f5fefe6 100644 --- a/src/core/constraints.jl +++ b/src/core/constraints.jl @@ -36,13 +36,6 @@ struct CommitmentConstraint <: ConstraintType end struct CopperPlateBalanceConstraint <: ConstraintType end struct DurationConstraint <: ConstraintType end struct EnergyBalanceConstraint <: ConstraintType end -struct EnergyBudgetConstraint <: ConstraintType end -struct EnergyCapacityConstraint <: ConstraintType end -struct EnergyCapacityDownConstraint <: ConstraintType end -struct EnergyCapacityUpConstraint <: ConstraintType end -struct EnergyLimitConstraint <: ConstraintType end # not being used -struct EnergyTargetConstraint <: ConstraintType end -struct EnergyShortageVariableLimitsConstraint <: ConstraintType end # not being used struct EqualityConstraint <: ConstraintType end struct FeedforwardSemiContinousConstraint <: ConstraintType end struct FeedforwardIntegralLimitConstraint <: ConstraintType end diff --git a/src/core/variables.jl b/src/core/variables.jl index 852bed4ab8..44176fa596 100644 --- a/src/core/variables.jl +++ b/src/core/variables.jl @@ -72,34 +72,6 @@ Docs abbreviation: ``E`` """ struct EnergyVariable <: VariableType end -""" -Struct to dispatch the creation of a variable for energy storage level (state of charge) of upper reservoir - -Docs abbreviation: ``E^{up}`` -""" -struct EnergyVariableUp <: VariableType end - -""" -Struct to dispatch the creation of a variable for energy storage level (state of charge) of lower reservoir - -Docs abbreviation: ``E^{down}`` -""" -struct EnergyVariableDown <: VariableType end - -""" -Struct to dispatch the creation of a slack variable for energy storage levels < target storage levels - -Docs abbreviation: ``E^{shortage}`` -""" -struct EnergyShortageVariable <: VariableType end - -""" -Struct to dispatch the creation of a slack variable for energy storage levels > target storage levels - -Docs abbreviation: ``E^{surplus}`` -""" -struct EnergySurplusVariable <: VariableType end - struct LiftVariable <: VariableType end """ @@ -132,13 +104,6 @@ struct ActivePowerReserveVariable <: VariableType end struct ServiceRequirementVariable <: VariableType end -""" -Struct to dispatch the creation of energy (water) spillage variable representing energy released from a storage/reservoir not injected into the network - -Docs abbreviation: ``S`` -""" -struct WaterSpillageVariable <: VariableType end - struct StartVariable <: VariableType end struct StopVariable <: VariableType end @@ -225,14 +190,9 @@ convert_result_to_natural_units(::Type{PowerAboveMinimumVariable}) = true convert_result_to_natural_units(::Type{ActivePowerInVariable}) = true convert_result_to_natural_units(::Type{ActivePowerOutVariable}) = true convert_result_to_natural_units(::Type{EnergyVariable}) = true -convert_result_to_natural_units(::Type{EnergyVariableUp}) = true -convert_result_to_natural_units(::Type{EnergyVariableDown}) = true -convert_result_to_natural_units(::Type{EnergyShortageVariable}) = true -convert_result_to_natural_units(::Type{EnergySurplusVariable}) = true convert_result_to_natural_units(::Type{ReactivePowerVariable}) = true convert_result_to_natural_units(::Type{ActivePowerReserveVariable}) = true convert_result_to_natural_units(::Type{ServiceRequirementVariable}) = true -# convert_result_to_natural_units(::Type{WaterSpillageVariable }) = true # TODO: is this pu? convert_result_to_natural_units(::Type{AreaMismatchVariable}) = true convert_result_to_natural_units(::Type{DeltaActivePowerUpVariable}) = true convert_result_to_natural_units(::Type{DeltaActivePowerDownVariable}) = true diff --git a/src/devices_models/devices/common/objective_functions.jl b/src/devices_models/devices/common/objective_functions.jl index 87bf5faca2..52b56a17eb 100644 --- a/src/devices_models/devices/common/objective_functions.jl +++ b/src/devices_models/devices/common/objective_functions.jl @@ -76,29 +76,6 @@ function add_proportional_cost!( return end -function add_proportional_cost!( - container::OptimizationContainer, - ::U, - devices::IS.FlattenIteratorWrapper{T}, - ::V, -) where { - T <: PSY.Component, - U <: Union{EnergySurplusVariable, EnergyShortageVariable}, - V <: AbstractDeviceFormulation, -} - base_p = get_base_power(container) - multiplier = objective_function_multiplier(U(), V()) - for d in devices - op_cost_data = PSY.get_operation_cost(d) - cost_term = proportional_cost(op_cost_data, U(), d, V()) - iszero(cost_term) && continue - for t in get_time_steps(container) - _add_proportional_term!(container, U(), d, cost_term * multiplier * base_p, t) - end - end - return -end - function add_proportional_cost!( container::OptimizationContainer, ::U, diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 69e861b2c7..95cd47efec 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -48,14 +48,10 @@ initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::Abstract ########################Objective Function################################################## proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_surplus_cost(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_shortage_cost(cost) objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::EnergySurplusVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_NEGATIVE -objective_function_multiplier(::EnergyShortageVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE diff --git a/src/feedforward/feedforward_arguments.jl b/src/feedforward/feedforward_arguments.jl index 33d62e15b7..adad3f4a18 100644 --- a/src/feedforward/feedforward_arguments.jl +++ b/src/feedforward/feedforward_arguments.jl @@ -69,16 +69,3 @@ function _add_feedforward_arguments!( ) return end - -function _add_feedforward_arguments!( - container::OptimizationContainer, - model::DeviceModel, - devices::IS.FlattenIteratorWrapper{T}, - ff::EnergyTargetFeedforward, -) where {T <: PSY.Component} - parameter_type = get_default_parameter_type(ff, T) - add_parameters!(container, parameter_type, ff, model, devices) - # Enabling this FF requires the addition of an extra variable - add_variables!(container, EnergyShortageVariable, devices, get_formulation(model)()) - return -end diff --git a/src/feedforward/feedforward_constraints.jl b/src/feedforward/feedforward_constraints.jl index 200f9988da..19b2a3c935 100644 --- a/src/feedforward/feedforward_constraints.jl +++ b/src/feedforward/feedforward_constraints.jl @@ -524,70 +524,3 @@ function add_feedforward_constraints!( end return end - -@doc raw""" - add_feedforward_constraints( - container::OptimizationContainer, - ::DeviceModel, - devices::IS.FlattenIteratorWrapper{T}, - ff::EnergyTargetFeedforward, - ) where {T <: PSY.Component} - -Constructs a equality constraint to a fix a variable in one model using the variable value from other model results. - - -``` variable[var_name, t] + slack[var_name, t] >= param[var_name, t] ``` - -# LaTeX - -`` x + slack >= param`` - -# Arguments -* container::OptimizationContainer : the optimization_container model built in PowerSimulations -* model::DeviceModel : the device model -* devices::IS.FlattenIteratorWrapper{T} : list of devices -* ff::EnergyTargetFeedforward : a instance of the FixValue Feedforward -""" -function add_feedforward_constraints!( - container::OptimizationContainer, - ::DeviceModel, - devices::IS.FlattenIteratorWrapper{T}, - ff::EnergyTargetFeedforward, -) where {T <: PSY.Component} - time_steps = get_time_steps(container) - parameter_type = get_default_parameter_type(ff, T) - param = get_parameter_array(container, parameter_type(), T) - multiplier = get_parameter_multiplier_array(container, parameter_type(), T) - target_period = ff.target_period - penalty_cost = ff.penalty_cost - for var in get_affected_values(ff) - variable = get_variable(container, var) - slack_var = get_variable(container, EnergyShortageVariable(), T) - set_name, set_time = JuMP.axes(variable) - IS.@assert_op set_name == [PSY.get_name(d) for d in devices] - IS.@assert_op set_time == time_steps - - var_type = get_entry_type(var) - con_ub = add_constraints_container!( - container, - FeedforwardEnergyTargetConstraint(), - T, - set_name; - meta = "$(var_type)target", - ) - - for d in devices - name = PSY.get_name(d) - con_ub[name] = JuMP.@constraint( - container.JuMPmodel, - variable[name, target_period] + slack_var[name, target_period] >= - param[name, target_period] * multiplier[name, target_period] - ) - add_to_objective_invariant_expression!( - container, - slack_var[name, target_period] * penalty_cost, - ) - end - end - return -end From e0795228eb173fe076d467cd0862023b1f4b4d6f Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 16:39:07 -0600 Subject: [PATCH 186/370] more hydro removal --- docs/src/api/PowerSimulations.md | 8 ++--- src/PowerSimulations.jl | 2 -- src/core/initial_conditions.jl | 2 -- src/core/parameters.jl | 27 ----------------- .../add_initial_condition.jl | 4 +-- ...itial_conditions_update_in_memory_store.jl | 28 ------------------ .../initial_condition_update_simulation.jl | 29 ------------------- test/test_simulation_results.jl | 2 -- 8 files changed, 4 insertions(+), 98 deletions(-) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index f4ead20864..352987d85a 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -260,19 +260,15 @@ FeedforwardEnergyTargetConstraint # Parameters -### Time Series Parameters +## Time Series Parameters ```@docs ActivePowerTimeSeriesParameter ReactivePowerTimeSeriesParameter RequirementTimeSeriesParameter -EnergyTargetTimeSeriesParameter -EnergyBudgetTimeSeriesParameter -InflowTimeSeriesParameter -OutflowTimeSeriesParameter ``` -### Variable Value Parameters +## Variable Value Parameters ```@docs UpperBoundValueParameter diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 68a74a029f..514c4e3a0b 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -304,8 +304,6 @@ export StartupTimeLimitTemperatureConstraint export ActivePowerTimeSeriesParameter export ReactivePowerTimeSeriesParameter export RequirementTimeSeriesParameter -export EnergyTargetTimeSeriesParameter -export EnergyBudgetTimeSeriesParameter # Feedforward Parameters export OnStatusParameter diff --git a/src/core/initial_conditions.jl b/src/core/initial_conditions.jl index e1ba803d08..59a2fdc68a 100644 --- a/src/core/initial_conditions.jl +++ b/src/core/initial_conditions.jl @@ -158,6 +158,4 @@ struct DeviceStatus <: InitialConditionType end struct InitialTimeDurationOn <: InitialConditionType end struct InitialTimeDurationOff <: InitialConditionType end struct InitialEnergyLevel <: InitialConditionType end -struct InitialEnergyLevelUp <: InitialConditionType end -struct InitialEnergyLevelDown <: InitialConditionType end struct AreaControlError <: InitialConditionType end diff --git a/src/core/parameters.jl b/src/core/parameters.jl index 2e7975a430..9392294d80 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -281,26 +281,6 @@ Paramter to define requirement time series """ struct RequirementTimeSeriesParameter <: TimeSeriesParameter end -""" -Parameter to define energy storage target level time series -""" -struct EnergyTargetTimeSeriesParameter <: TimeSeriesParameter end - -""" -Parameter to define energy budget time series -""" -struct EnergyBudgetTimeSeriesParameter <: TimeSeriesParameter end - -""" -Parameter to define energy inflow to storage or reservoir time series -""" -struct InflowTimeSeriesParameter <: TimeSeriesParameter end - -""" -Parameter to define energy outflow from storage or reservoir time series -""" -struct OutflowTimeSeriesParameter <: TimeSeriesParameter end - abstract type VariableValueParameter <: RightHandSideParameter end struct UpperBoundValueParameter <: VariableValueParameter end @@ -308,7 +288,6 @@ struct LowerBoundValueParameter <: VariableValueParameter end struct OnStatusParameter <: VariableValueParameter end struct EnergyLimitParameter <: VariableValueParameter end struct FixValueParameter <: VariableValueParameter end -struct EnergyTargetParameter <: VariableValueParameter end struct CostFunctionParameter <: ObjectiveFunctionParameter end @@ -322,11 +301,5 @@ convert_result_to_natural_units(::Type{<:ParameterType}) = false convert_result_to_natural_units(::Type{ActivePowerTimeSeriesParameter}) = true convert_result_to_natural_units(::Type{ReactivePowerTimeSeriesParameter}) = true convert_result_to_natural_units(::Type{RequirementTimeSeriesParameter}) = true -convert_result_to_natural_units(::Type{EnergyTargetTimeSeriesParameter}) = true -convert_result_to_natural_units(::Type{EnergyBudgetTimeSeriesParameter}) = true -#convert_result_to_natural_units(::Type{InflowTimeSeriesParameter}) = true # TODO: is this pu? -#convert_result_to_natural_units(::Type{OutflowTimeSeriesParameter}) = true # TODO: is this pu? convert_result_to_natural_units(::Type{UpperBoundValueParameter}) = true convert_result_to_natural_units(::Type{LowerBoundValueParameter}) = true -convert_result_to_natural_units(::Type{EnergyLimitParameter}) = true -convert_result_to_natural_units(::Type{EnergyTargetParameter}) = true diff --git a/src/initial_conditions/add_initial_condition.jl b/src/initial_conditions/add_initial_condition.jl index ebc83377a3..5dd0dba455 100644 --- a/src/initial_conditions/add_initial_condition.jl +++ b/src/initial_conditions/add_initial_condition.jl @@ -162,7 +162,7 @@ function _get_initial_conditions_value( T <: InitialCondition{U, JuMP.VariableRef}, V <: Union{AbstractDeviceFormulation, AbstractServiceFormulation}, W <: PSY.Component, -} where {U <: Union{InitialEnergyLevel, InitialEnergyLevelUp, InitialEnergyLevelDown}} +} where {U <: InitialEnergyLevel} var_type = initial_condition_variable(U(), component, V()) val = initial_condition_default(U(), component, V()) @debug "Device $(PSY.get_name(component)) initialized DeviceStatus as $var_type" _group = @@ -180,7 +180,7 @@ function _get_initial_conditions_value( T <: InitialCondition{U, Float64}, V <: Union{AbstractDeviceFormulation, AbstractServiceFormulation}, W <: PSY.Component, -} where {U <: Union{InitialEnergyLevel, InitialEnergyLevelUp, InitialEnergyLevelDown}} +} where {U <: InitialEnergyLevel} var_type = initial_condition_variable(U(), component, V()) val = initial_condition_default(U(), component, V()) @debug "Device $(PSY.get_name(component)) initialized DeviceStatus as $var_type" _group = diff --git a/src/operation/initial_conditions_update_in_memory_store.jl b/src/operation/initial_conditions_update_in_memory_store.jl index b8767a273c..96e96a4f25 100644 --- a/src/operation/initial_conditions_update_in_memory_store.jl +++ b/src/operation/initial_conditions_update_in_memory_store.jl @@ -85,31 +85,3 @@ function update_initial_conditions!( end return end - -function update_initial_conditions!( - ics::Vector{T}, - store::EmulationModelStore, - ::Dates.Millisecond, -) where { - T <: InitialCondition{InitialEnergyLevelUp, S}, -} where {S <: Union{Float64, JuMP.VariableRef}} - for ic in ics - var_val = get_variable_value(store, EnergyVariableUp(), get_component_type(ic)) - set_ic_quantity!(ic, get_last_recorded_value(var_val)[get_component_name(ic)]) - end - return -end - -function update_initial_conditions!( - ics::Vector{T}, - store::EmulationModelStore, - ::Dates.Millisecond, -) where { - T <: InitialCondition{InitialEnergyLevelDown, S}, -} where {S <: Union{Float64, JuMP.VariableRef}} - for ic in ics - var_val = get_variable_value(store, EnergyVariableDown(), get_component_type(ic)) - set_ic_quantity!(ic, get_last_recorded_value(var_val)[get_component_name(ic)]) - end - return -end diff --git a/src/simulation/initial_condition_update_simulation.jl b/src/simulation/initial_condition_update_simulation.jl index 98df79210b..7d444cf609 100644 --- a/src/simulation/initial_condition_update_simulation.jl +++ b/src/simulation/initial_condition_update_simulation.jl @@ -141,32 +141,3 @@ function update_initial_conditions!( end return end - -function update_initial_conditions!( - ics::Vector{T}, - state::SimulationState, - ::Dates.Millisecond, -) where { - T <: InitialCondition{InitialEnergyLevelUp, S}, -} where {S <: Union{Float64, JuMP.VariableRef}} - for ic in ics - var_val = get_system_state_value(state, EnergyVariableUp(), get_component_type(ic)) - set_ic_quantity!(ic, var_val[get_component_name(ic)]) - end - return -end - -function update_initial_conditions!( - ics::Vector{T}, - state::SimulationState, - ::Dates.Millisecond, -) where { - T <: InitialCondition{InitialEnergyLevelDown, S}, -} where {S <: Union{Float64, JuMP.VariableRef}} - for ic in ics - var_val = - get_system_state_value(state, EnergyVariableDown(), get_component_type(ic)) - set_ic_quantity!(ic, var_val[get_component_name(ic)]) - end - return -end diff --git a/test/test_simulation_results.jl b/test/test_simulation_results.jl index 4b8816d043..f47134d04e 100644 --- a/test/test_simulation_results.jl +++ b/test/test_simulation_results.jl @@ -81,10 +81,8 @@ NATURAL_UNITS_VALUES = [ "ActivePowerTimeSeriesParameter__HydroEnergyReservoir", "ActivePowerTimeSeriesParameter__RenewableDispatch", "ActivePowerTimeSeriesParameter__InterruptiblePowerLoad", - "EnergyLimitParameter__HydroEnergyReservoir", "SystemBalanceSlackDown__System", "SystemBalanceSlackUp__System", - "EnergyBudgetTimeSeriesParameter__HydroEnergyReservoir", ] function compare_results(rpath, epath, model, field, name, timestamp) From 1cc229c4d106e48199a8431bbe7dd2acbd63442d Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 17:04:30 -0600 Subject: [PATCH 187/370] comment out repeated code with HydroPowerSims --- .../device_constructors/hydrogeneration_constructor.jl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index 75673eba77..5d04b0be29 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -70,6 +70,7 @@ function construct_device!( return end +#= """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation """ @@ -132,6 +133,7 @@ function construct_device!( return end + function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -178,6 +180,7 @@ function construct_device!( return end +=# """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation @@ -191,7 +194,7 @@ function construct_device!( network_model::NetworkModel{S}, ) where { H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, + D <: HydroDispatchRunOfRiver, S <: PM.AbstractActivePowerModel, } devices = @@ -232,6 +235,7 @@ function construct_device!( return end +#= function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -270,6 +274,7 @@ function construct_device!( add_constraint_dual!(container, sys, model) return end +=# """ Construct model for HydroGen with RunOfRiver Commitment Formulation From 69d45a27e6eedca39c58adff195d47f172743220 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 17:11:09 -0600 Subject: [PATCH 188/370] formatter --- .../device_constructors/hydrogeneration_constructor.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index 5d04b0be29..4e504bb613 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -133,7 +133,6 @@ function construct_device!( return end - function construct_device!( container::OptimizationContainer, sys::PSY.System, From 06cfd93419a47700afae33de9a9f064715afb529 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 13 Jul 2023 10:47:27 -0600 Subject: [PATCH 189/370] fix hydro tests and references --- docs/src/tutorials/decision_problem.md | 2 +- .../hydrogeneration_constructor.jl | 12 +++++------- src/devices_models/devices/hydro_generation.jl | 9 +-------- src/simulation/simulation_results.jl | 1 - 4 files changed, 7 insertions(+), 17 deletions(-) diff --git a/docs/src/tutorials/decision_problem.md b/docs/src/tutorials/decision_problem.md index 52cc8c4886..584a986811 100644 --- a/docs/src/tutorials/decision_problem.md +++ b/docs/src/tutorials/decision_problem.md @@ -64,7 +64,7 @@ set_device_model!(template_uc, ThermalStandard, ThermalStandardUnitCommitment) set_device_model!(template_uc, RenewableDispatch, RenewableFullDispatch) set_device_model!(template_uc, PowerLoad, StaticPowerLoad) set_device_model!(template_uc, HydroDispatch, FixedOutput) -set_device_model!(template_uc, HydroEnergyReservoir, HydroDispatchRunOfRiver) +set_device_model!(template_uc, HydroDispatchRunOfRiver, HydroDispatchRunOfRiver) set_device_model!(template_uc, RenewableFix, FixedOutput) ``` diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index 4e504bb613..dd43264c65 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -70,7 +70,6 @@ function construct_device!( return end -#= """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation """ @@ -82,7 +81,7 @@ function construct_device!( network_model::NetworkModel{S}, ) where { H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, + D <: Union{HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}, S <: PM.AbstractPowerModel, } devices = @@ -141,7 +140,7 @@ function construct_device!( network_model::NetworkModel{S}, ) where { H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, + D <: Union{HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}, S <: PM.AbstractPowerModel, } devices = @@ -179,7 +178,6 @@ function construct_device!( return end -=# """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation @@ -234,7 +232,7 @@ function construct_device!( return end -#= + function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -243,7 +241,7 @@ function construct_device!( network_model::NetworkModel{S}, ) where { H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, + D <: HydroDispatchRunOfRiver, S <: PM.AbstractActivePowerModel, } devices = @@ -273,7 +271,7 @@ function construct_device!( add_constraint_dual!(container, sys, model) return end -=# + """ Construct model for HydroGen with RunOfRiver Commitment Formulation diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 95cd47efec..34a8ae1de8 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -62,13 +62,6 @@ variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGe #! format: on -function get_initial_conditions_device_model( - ::OperationModel, - model::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroEnergyReservoir} - return model -end - function get_initial_conditions_device_model( ::OperationModel, ::DeviceModel{T, <:AbstractHydroFormulation}, @@ -89,7 +82,7 @@ end function get_default_attributes( ::Type{T}, ::Type{D}, -) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} +) where {T <: PSY.HydroGen, D <:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}} return Dict{String, Any}("reservation" => false) end diff --git a/src/simulation/simulation_results.jl b/src/simulation/simulation_results.jl index 6bffc75725..accbb0a181 100644 --- a/src/simulation/simulation_results.jl +++ b/src/simulation/simulation_results.jl @@ -234,7 +234,6 @@ An example JSON file demonstrating possible options is below. Note that `start_t "name": "ED", "variables": [ "P__ThermalStandard", - "E__HydroEnergyReservoir" ], "parameters": [ "all" From f5e2b7a2e3e55a268d954fb444adf09b547cb6b6 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 13 Jul 2023 10:50:41 -0600 Subject: [PATCH 190/370] formatter --- .../device_constructors/hydrogeneration_constructor.jl | 2 -- src/devices_models/devices/hydro_generation.jl | 5 ++++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index dd43264c65..534038d7f6 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -232,7 +232,6 @@ function construct_device!( return end - function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -272,7 +271,6 @@ function construct_device!( return end - """ Construct model for HydroGen with RunOfRiver Commitment Formulation """ diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 34a8ae1de8..2767ff8095 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -82,7 +82,10 @@ end function get_default_attributes( ::Type{T}, ::Type{D}, -) where {T <: PSY.HydroGen, D <:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}} +) where { + T <: PSY.HydroGen, + D <: Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}, +} return Dict{String, Any}("reservation" => false) end From 124eb10e9ca1304d32cdfcbb1e42e699fa762673 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 13 Jul 2023 10:57:12 -0600 Subject: [PATCH 191/370] change abstract type call --- src/devices_models/devices/hydro_generation.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 2767ff8095..9773698f0e 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -65,8 +65,8 @@ variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGe function get_initial_conditions_device_model( ::OperationModel, ::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroDispatch} - return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) +) where {T <: PSY.HydroGen} + return DeviceModel(T, HydroDispatchRunOfRiver) end function get_default_time_series_names( From 40670aaa267238451b486db23ab6f13acb1a0358 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 12:25:19 -0600 Subject: [PATCH 192/370] use reserves in reserve models --- src/services_models/reserves.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/services_models/reserves.jl b/src/services_models/reserves.jl index cbc1251d3f..33988203cc 100644 --- a/src/services_models/reserves.jl +++ b/src/services_models/reserves.jl @@ -37,7 +37,7 @@ uses_compact_power(::PSY.ReserveDemandCurve, ::StepwiseCostReserve)=false function get_initial_conditions_service_model( ::OperationModel, ::ServiceModel{T, D}, -) where {T <: PSY.Service, D <: AbstractServiceFormulation} +) where {T <: PSY.Reserve, D <: AbstractReservesFormulation} return ServiceModel(T, D) end @@ -60,13 +60,13 @@ function get_default_time_series_names( end function get_default_time_series_names( - ::Type{<:PSY.Service}, - ::Type{<:AbstractServiceFormulation}, + ::Type{<:PSY.Reserve}, + ::Type{<:AbstractReservesFormulation}, ) return Dict{Type{<:TimeSeriesParameter}, String}() end -function get_default_attributes(::Type{<:PSY.Service}, ::Type{<:AbstractServiceFormulation}) +function get_default_attributes(::Type{<:PSY.Reserve}, ::Type{<:AbstractReservesFormulation}) return Dict{String, Any}() end From ab4364f3c53eae55d08a322d1e05b426fd0a70e7 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 12:25:29 -0600 Subject: [PATCH 193/370] add interface formulations --- src/PowerSimulations.jl | 3 +++ src/core/formulations.jl | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 41a1f0c63b..061d9aab5c 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -35,6 +35,8 @@ export StepwiseCostReserve export NonSpinningReserve export PIDSmoothACE export GroupReserve +export ConstantMaxInterfaceFlow + ######## Branch Models ######## export StaticBranch export StaticBranchBounds @@ -535,6 +537,7 @@ include("devices_models/devices/regulation_device.jl") # Services Models include("services_models/agc.jl") include("services_models/reserves.jl") +include("services_models/transmission_interface.jl") include("services_models/group_reserve.jl") include("services_models/service_slacks.jl") include("services_models/services_constructor.jl") diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 7522280c51..f06cec34a5 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -220,3 +220,5 @@ struct RangeReserve <: AbstractReservesFormulation end struct StepwiseCostReserve <: AbstractReservesFormulation end struct RampReserve <: AbstractReservesFormulation end struct NonSpinningReserve <: AbstractReservesFormulation end + +struct ConstantMaxInterfaceFlow <: AbstractServiceFormulation end From 23b6efd1b3372b10f4a3a023a5bab5dcc1661188 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:55:57 -0600 Subject: [PATCH 194/370] add new expression types --- src/core/expressions.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/expressions.jl b/src/core/expressions.jl index 89c6a8df15..ab981f4f45 100644 --- a/src/core/expressions.jl +++ b/src/core/expressions.jl @@ -47,9 +47,12 @@ struct ReserveRangeExpressionUB <: RangeConstraintUBExpressions end struct ComponentActivePowerRangeExpressionUB <: RangeConstraintUBExpressions end struct ComponentReserveUpBalanceExpression <: ExpressionType end struct ComponentReserveDownBalanceExpression <: ExpressionType end +struct InterfaceTotalFlow <: ExpressionType end should_write_resulting_value(::Type{<:ExpressionType}) = false should_write_resulting_value(::Type{<:CostExpressions}) = true +should_write_resulting_value(::Type{InterfaceTotalFlow}) = true should_write_resulting_value(::Type{RawACE}) = true convert_result_to_natural_units(::Type{<:ExpressionType}) = false +convert_result_to_natural_units(::Type{InterfaceTotalFlow}) = true From d791b06c5f62f72d8721f0452017cdbc6630ffe7 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:56:05 -0600 Subject: [PATCH 195/370] remove stale code --- .../constructor_validations.jl | 55 ------------------- 1 file changed, 55 deletions(-) diff --git a/src/devices_models/device_constructors/constructor_validations.jl b/src/devices_models/device_constructors/constructor_validations.jl index 50fd4a3bff..dbf142ae00 100644 --- a/src/devices_models/device_constructors/constructor_validations.jl +++ b/src/devices_models/device_constructors/constructor_validations.jl @@ -10,58 +10,3 @@ function validate_available_devices( PSY.check_components(system, devices) return true end - -function validate_service!( - model::ServiceModel{S, <:AbstractServiceFormulation}, - incompatible_device_types::Set{<:DataType}, - sys::PSY.System, -) where {S <: PSY.Service} - service = PSY.get_component(S, sys, get_service_name(model)) - if service === nothing - @info "The data doesn't include services of type $(S) and name $(get_service_name(model)), consider changing the service models" _group = - LOG_GROUP_MODELS_VALIDATION - return false - end - - PSY.check_components(sys, service) - services_mapping = PSY.get_contributing_device_mapping(sys) - - contributing_devices_ = - services_mapping[(type = S, name = PSY.get_name(service))].contributing_devices - contributing_devices = [ - d for d in contributing_devices_ if - typeof(d) ∉ incompatible_device_types && PSY.get_available(d) - ] - if isempty(contributing_devices) - @warn "The contributing devices for service $(PSY.get_name(service)) is empty, consider removing the service from the system" _group = - LOG_GROUP_MODELS_VALIDATION - return false - end - - PSY.check_components(sys, contributing_devices) - return true -end - -function validate_services!( - model::ServiceModel{S, <:AbstractServiceFormulation}, - ::Vector{<:DataType}, - sys::PSY.System, -) where {S <: PSY.StaticReserveGroup} - service = PSY.get_component(S, sys, get_service_name(model)) - if service === nothing - @info "The data doesn't include services of type $(S) and name $(get_service_name(model)), consider changing the service models" _group = - LOG_GROUP_MODELS_VALIDATION - return false - end - - PSY.check_components(sys, service) - contributing_services = PSY.get_contributing_services(s) - if isempty(contributing_services) - @warn "The contributing services for group service $(PSY.get_name(service)) is empty, consider removing the group service from the system" _group = - LOG_GROUP_MODELS_VALIDATION - return false - end - - PSY.check_components(sys, contributing_devices) - return true -end From 4471756b01dfed7551f480244571ddd38f9af23a Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:56:52 -0600 Subject: [PATCH 196/370] update constructors --- src/services_models/services_constructor.jl | 46 ++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index ecd2a46453..a943ced264 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -30,7 +30,6 @@ function construct_services!( continue end isempty(get_contributing_devices(service_model)) && continue - get_contributing_devices(service_model) construct_service!( container, sys, @@ -463,3 +462,48 @@ function construct_service!( add_constraint_dual!(container, sys, model) return end + +function construct_service!( + container::OptimizationContainer, + sys::PSY.System, + ::ArgumentConstructStage, + model::ServiceModel{SR, ConstantMaxInterfaceFlow}, + devices_template::Dict{Symbol, DeviceModel}, + incompatible_device_types::Set{<:DataType}, +) where {SR <: PSY.TransmissionInterface} + add_to_expression!( + container, + InterfaceTotalFlow, + FlowActivePowerVariable, + devices, + model, + network_model, + ) + add_feedforward_arguments!(container, model, service) + return +end + +function construct_service!( + container::OptimizationContainer, + sys::PSY.System, + ::ModelConstructStage, + model::ServiceModel{SR, ConstantMaxInterfaceFlow}, + devices_template::Dict{Symbol, DeviceModel}, + incompatible_device_types::Set{<:DataType}, +) where {SR <: PSY.TransmissionInterface} + @error("here2") + error() + name = get_service_name(model) + service = PSY.get_component(SR, sys, name) + contributing_devices = get_contributing_devices(model) + + add_constraints!(container, RequirementConstraint, service, contributing_devices, model) + + objective_function!(container, service, model) + + add_feedforward_constraints!(container, model, service) + + add_constraint_dual!(container, sys, model) + + return +end From f53fb87a114ec735aadf445e29c97f385487c163 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:57:10 -0600 Subject: [PATCH 197/370] wip: add interface code --- src/services_models/transmission_interface.jl | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/services_models/transmission_interface.jl diff --git a/src/services_models/transmission_interface.jl b/src/services_models/transmission_interface.jl new file mode 100644 index 0000000000..a8c6edb350 --- /dev/null +++ b/src/services_models/transmission_interface.jl @@ -0,0 +1,19 @@ +function get_default_time_series_names( + ::Type{PSY.TransmissionInterface}, + ::Type{ConstantMaxInterfaceFlow}, +) + return Dict{Type{<:TimeSeriesParameter}, String}() +end + +function get_default_attributes( + ::Type{<:PSY.TransmissionInterface}, + ::Type{ConstantMaxInterfaceFlow}) + return Dict{String, Any}() +end + +function get_initial_conditions_service_model( + ::OperationModel, + ::ServiceModel{T, D}, +) where {T <: PSY.TransmissionInterface, D <: ConstantMaxInterfaceFlow} + return ServiceModel(T, D) +end From e8e0e03a9b74fafcf1b40c0f7ea88b8c428fcf80 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:57:33 -0600 Subject: [PATCH 198/370] use abstracr service --- src/devices_models/devices/common/add_variable.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/devices/common/add_variable.jl b/src/devices_models/devices/common/add_variable.jl index 6ea4ecdcf1..c9bb403fe3 100644 --- a/src/devices_models/devices/common/add_variable.jl +++ b/src/devices_models/devices/common/add_variable.jl @@ -107,7 +107,7 @@ function add_service_variable!( variable_type::T, service::U, contributing_devices::V, - formulation::AbstractReservesFormulation, + formulation::AbstractServiceFormulation, ) where { T <: VariableType, U <: PSY.Service, From 4ae5f89fb6308b4364ab1e7951da4d6f275a6609 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:57:49 -0600 Subject: [PATCH 199/370] use deepcopy to avoid issues with templace --- src/operation/decision_model.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index cd0fa9d1e3..8427b0fa7d 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -74,10 +74,11 @@ mutable struct DecisionModel{M <: DecisionProblem} <: OperationModel internal = ModelInternal( OptimizationContainer(sys, settings, jump_model, PSY.Deterministic), ) - finalize_template!(template, sys) + template_ = deepcopy(template) + finalize_template!(template_, sys) return new{M}( name, - template, + template_, sys, internal, DecisionModelStore(), From 2dc924af7cae0f670c3d634bc07aa80d8a567aa2 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:58:13 -0600 Subject: [PATCH 200/370] update servies model code --- src/operation/problem_template.jl | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/operation/problem_template.jl b/src/operation/problem_template.jl index 5e39f69525..9042cf03a1 100644 --- a/src/operation/problem_template.jl +++ b/src/operation/problem_template.jl @@ -183,7 +183,9 @@ function _populate_contributing_devices!(template::ProblemTemplate, sys::PSY.Sys isempty(service_models) && return device_models = get_device_models(template) + branch_models = get_branch_models(template) modeled_devices = Set(get_component_type(m) for m in values(device_models)) + union!(modeled_devices, Set(get_component_type(m) for m in values(branch_models))) incompatible_device_types = get_incompatible_devices(device_models) services_mapping = PSY.get_contributing_device_mapping(sys) for (service_key, service_model) in service_models @@ -198,7 +200,6 @@ function _populate_contributing_devices!(template::ProblemTemplate, sys::PSY.Sys end contributing_devices_ = services_mapping[(type = S, name = PSY.get_name(service))].contributing_devices - for d in contributing_devices_ _add_contributing_device_by_type!( service_model, @@ -234,9 +235,17 @@ function _modify_device_model!( end function _modify_device_model!( - devices_template::Dict{Symbol, DeviceModel}, - service_model::ServiceModel{<:PSY.ReserveNonSpinning, <:AbstractReservesFormulation}, - contributing_devices::Vector{<:PSY.Component}, + ::Dict{Symbol, DeviceModel}, + ::ServiceModel{<:PSY.ReserveNonSpinning, <:AbstractReservesFormulation}, + ::Vector{<:PSY.Component}, +) + return +end + +function _modify_device_model!( + ::Dict{Symbol, DeviceModel}, + ::ServiceModel{PSY.TransmissionInterface, ConstantMaxInterfaceFlow}, + ::Vector ) return end From 2b8ea6e6182fcdebd12c04f0f5f052191cc2c785 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 00:23:34 -0600 Subject: [PATCH 201/370] minor fix to slacks --- src/services_models/service_slacks.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services_models/service_slacks.jl b/src/services_models/service_slacks.jl index 12835d8d6f..1c6adafa35 100644 --- a/src/services_models/service_slacks.jl +++ b/src/services_models/service_slacks.jl @@ -13,7 +13,7 @@ function reserve_slacks( for t in time_steps variable[t] = JuMP.@variable( - container.JuMPmodel, + get_jump_model(container), base_name = "slack_{$(PSY.get_name(service)), $(t)}", lower_bound = 0.0 ) From 6fb93380ef52b59822bfc06ec402cea74c1ddc4b Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 00:23:51 -0600 Subject: [PATCH 202/370] more expression updates --- .../devices/common/add_to_expression.jl | 22 +++++++++++++++++++ src/services_models/services_constructor.jl | 4 ++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index ba24c91f15..a892466a48 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -753,6 +753,28 @@ function add_to_expression!( return end +function add_to_expression!( + container::OptimizationContainer, + ::Type{InterfaceTotalFlow}, + ::Type{FlowActivePowerVariable}, + devices::Vector{T}, + model::ServiceModel{PSY.TransmissionInterface, ConstantMaxInterfaceFlow} +) where {T <: PSY.Component} + services = get_available_components(TransmissionInterface, sys) + if !has_container_key(container, InterfaceTotalFlow, TransmissionInterface) + add_expressions!(container, InterfaceTotalFlow, services, model) + end + variable = get_variable(container, FlowActivePowerVariable(), X, service_name) + + expression = get_expression(container, T(), V) + for d in devices, t in get_time_steps(container) + name = PSY.get_name(d) + _add_to_jump_expression!(expression[name, t], variable[name, t], 1.0) + end + return +end + + function add_to_expression!( container::OptimizationContainer, ::Type{T}, diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index a943ced264..818c1ae52e 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -471,13 +471,13 @@ function construct_service!( devices_template::Dict{Symbol, DeviceModel}, incompatible_device_types::Set{<:DataType}, ) where {SR <: PSY.TransmissionInterface} + contributing_devices = get_contributing_devices(model) add_to_expression!( container, InterfaceTotalFlow, FlowActivePowerVariable, - devices, + contributing_devices, model, - network_model, ) add_feedforward_arguments!(container, model, service) return From d9ebe4cba5cdd302eb47fb78a3deca6c7e35475c Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 17:23:27 -0600 Subject: [PATCH 203/370] add interface flow constraint --- src/core/constraints.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/constraints.jl b/src/core/constraints.jl index 79da9e177c..7e0af2ef48 100644 --- a/src/core/constraints.jl +++ b/src/core/constraints.jl @@ -89,6 +89,7 @@ struct StartupTimeLimitTemperatureConstraint <: ConstraintType end struct PhaseAngleControlLimit <: ConstraintType end struct HVDCLossesAbsoluteValue <: ConstraintType end struct HVDCDirection <: ConstraintType end +struct InterfaceFlowLimit <: ConstraintType end abstract type PowerVariableLimitsConstraint <: ConstraintType end struct InputActivePowerVariableLimitsConstraint <: PowerVariableLimitsConstraint end From 7300a9f6cb7ae660fc5dc21cf694814c248d69e7 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 17:23:45 -0600 Subject: [PATCH 204/370] remove duplicate abstraction --- src/core/formulations.jl | 13 +++++++++++-- src/core/service_model.jl | 12 ------------ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/core/formulations.jl b/src/core/formulations.jl index f06cec34a5..6752ad5599 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -207,14 +207,23 @@ import PowerModels: QCRMPowerModel import PowerModels: QCLSPowerModel +""" +Abstract type for Service Formulations (a.k.a Models) + +# Example + +import PowerSimulations +const PSI = PowerSimulations +struct MyServiceFormulation <: PSI.AbstractServiceFormulation +""" abstract type AbstractServiceFormulation end +abstract type AbstractReservesFormulation <: AbstractServiceFormulation end + abstract type AbstractAGCFormulation <: AbstractServiceFormulation end struct PIDSmoothACE <: AbstractAGCFormulation end -abstract type AbstractReservesFormulation <: AbstractServiceFormulation end - struct GroupReserve <: AbstractReservesFormulation end struct RangeReserve <: AbstractReservesFormulation end struct StepwiseCostReserve <: AbstractReservesFormulation end diff --git a/src/core/service_model.jl b/src/core/service_model.jl index 08ed0c701b..6ea786fa81 100644 --- a/src/core/service_model.jl +++ b/src/core/service_model.jl @@ -1,15 +1,3 @@ -""" -Abstract type for Service Formulations (a.k.a Models) - -# Example - -import PowerSimulations -const PSI = PowerSimulations -struct MyServiceFormulation <: PSI.AbstractServiceFormulation -""" -abstract type AbstractServiceFormulation end -abstract type AbstractReservesFormulation <: AbstractServiceFormulation end - function _check_service_formulation( ::Type{D}, ) where {D <: Union{AbstractServiceFormulation, PSY.Service}} From 3f435a709887e9e143aa39046ed122c8db993a4f Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 18:39:50 -0600 Subject: [PATCH 205/370] fix problem population --- src/operation/problem_template.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/operation/problem_template.jl b/src/operation/problem_template.jl index 9042cf03a1..92e86e8fc5 100644 --- a/src/operation/problem_template.jl +++ b/src/operation/problem_template.jl @@ -245,7 +245,7 @@ end function _modify_device_model!( ::Dict{Symbol, DeviceModel}, ::ServiceModel{PSY.TransmissionInterface, ConstantMaxInterfaceFlow}, - ::Vector + ::Vector, ) return end @@ -269,7 +269,7 @@ function _populate_aggregated_service_model!(template::ProblemTemplate, sys::PSY attributes = get_attributes(service_model) use_slacks = service_model.use_slacks duals = service_model.duals - if get(attributes, "aggregated_service_model", false) + if pop!(attributes, "aggregated_service_model", false) delete!(services_template, key) D = get_component_type(service_model) B = get_formulation(service_model) @@ -284,6 +284,7 @@ function _populate_aggregated_service_model!(template::ProblemTemplate, sys::PSY PSY.get_name(service); use_slacks = use_slacks, duals = duals, + attributes = attributes, ), ) end From 8a804934488a122469b78f6053737ce5b9ea1559 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 18:40:05 -0600 Subject: [PATCH 206/370] use reserves abstraction in reserves --- src/services_models/reserves.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/services_models/reserves.jl b/src/services_models/reserves.jl index 33988203cc..f02c13f619 100644 --- a/src/services_models/reserves.jl +++ b/src/services_models/reserves.jl @@ -66,7 +66,10 @@ function get_default_time_series_names( return Dict{Type{<:TimeSeriesParameter}, String}() end -function get_default_attributes(::Type{<:PSY.Reserve}, ::Type{<:AbstractReservesFormulation}) +function get_default_attributes( + ::Type{<:PSY.Reserve}, + ::Type{<:AbstractReservesFormulation}, +) return Dict{String, Any}() end From 4f4af73285ef69a4a5c9a95d8e443d5c3660ac00 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 18:44:25 -0600 Subject: [PATCH 207/370] add constructor methods for interfaces --- src/services_models/services_constructor.jl | 44 ++++++++++----------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index 818c1ae52e..fd478750fc 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -66,7 +66,7 @@ function construct_services!( groupservice = key continue end - isempty(get_contributing_devices(service_model)) && continue + isempty(get_contributing_devices_map(service_model)) && continue construct_service!( container, sys, @@ -467,19 +467,20 @@ function construct_service!( container::OptimizationContainer, sys::PSY.System, ::ArgumentConstructStage, - model::ServiceModel{SR, ConstantMaxInterfaceFlow}, + model::ServiceModel{T, ConstantMaxInterfaceFlow}, devices_template::Dict{Symbol, DeviceModel}, incompatible_device_types::Set{<:DataType}, -) where {SR <: PSY.TransmissionInterface} - contributing_devices = get_contributing_devices(model) - add_to_expression!( +) where {T <: PSY.TransmissionInterface} + # contributing_devices_map = get_contributing_devices_map(model) + interfaces = PSY.get_name.(get_available_components(T, sys)) + lazy_container_addition!( container, - InterfaceTotalFlow, - FlowActivePowerVariable, - contributing_devices, - model, + InterfaceTotalFlow(), + T, + interfaces, + get_time_steps(container), ) - add_feedforward_arguments!(container, model, service) + #add_feedforward_arguments!(container, model, service) return end @@ -487,23 +488,22 @@ function construct_service!( container::OptimizationContainer, sys::PSY.System, ::ModelConstructStage, - model::ServiceModel{SR, ConstantMaxInterfaceFlow}, + model::ServiceModel{T, ConstantMaxInterfaceFlow}, devices_template::Dict{Symbol, DeviceModel}, incompatible_device_types::Set{<:DataType}, -) where {SR <: PSY.TransmissionInterface} - @error("here2") - error() +) where {T <: PSY.TransmissionInterface} name = get_service_name(model) - service = PSY.get_component(SR, sys, name) - contributing_devices = get_contributing_devices(model) - - add_constraints!(container, RequirementConstraint, service, contributing_devices, model) - - objective_function!(container, service, model) + service = PSY.get_component(T, sys, name) + add_to_expression!( + container, + InterfaceTotalFlow, + FlowActivePowerVariable, + service, + model, + ) + add_constraints!(container, InterfaceFlowLimit, service, model) add_feedforward_constraints!(container, model, service) - add_constraint_dual!(container, sys, model) - return end From f651f4e95854869b03e2819c654cf3c09bbd257f Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 18:44:37 -0600 Subject: [PATCH 208/370] add methods for interface --- .../devices/common/add_to_expression.jl | 32 +++++++++++-------- src/feedforward/feedforward_constraints.jl | 15 ++++++++- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index a892466a48..3b61b16f47 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -757,24 +757,28 @@ function add_to_expression!( container::OptimizationContainer, ::Type{InterfaceTotalFlow}, ::Type{FlowActivePowerVariable}, - devices::Vector{T}, - model::ServiceModel{PSY.TransmissionInterface, ConstantMaxInterfaceFlow} -) where {T <: PSY.Component} - services = get_available_components(TransmissionInterface, sys) - if !has_container_key(container, InterfaceTotalFlow, TransmissionInterface) - add_expressions!(container, InterfaceTotalFlow, services, model) - end - variable = get_variable(container, FlowActivePowerVariable(), X, service_name) - - expression = get_expression(container, T(), V) - for d in devices, t in get_time_steps(container) - name = PSY.get_name(d) - _add_to_jump_expression!(expression[name, t], variable[name, t], 1.0) + service::PSY.TransmissionInterface, + model::ServiceModel{PSY.TransmissionInterface, ConstantMaxInterfaceFlow}, +) + expression = get_expression(container, InterfaceTotalFlow(), PSY.TransmissionInterface) + service_name = get_service_name(model) + for (device_type, devices) in get_contributing_devices_map(model) + variable = get_variable(container, FlowActivePowerVariable(), device_type) + for d in devices + name = PSY.get_name(d) + direction = get(PSY.get_direction_mapping(service), name, 1.0) + for t in get_time_steps(container) + _add_to_jump_expression!( + expression[service_name, t], + variable[name, t], + direction, + ) + end + end end return end - function add_to_expression!( container::OptimizationContainer, ::Type{T}, diff --git a/src/feedforward/feedforward_constraints.jl b/src/feedforward/feedforward_constraints.jl index 200f9988da..ee676f288d 100644 --- a/src/feedforward/feedforward_constraints.jl +++ b/src/feedforward/feedforward_constraints.jl @@ -12,7 +12,7 @@ end function add_feedforward_constraints!( container::OptimizationContainer, - model::ServiceModel, + model::ServiceModel{V, <:AbstractReservesFormulation}, ::V, ) where {V <: PSY.AbstractReserve} for ff in get_feedforwards(model) @@ -23,6 +23,19 @@ function add_feedforward_constraints!( return end +function add_feedforward_constraints!( + container::OptimizationContainer, + model::ServiceModel, + ::V, +) where {V <: PSY.Service} + for ff in get_feedforwards(model) + @debug "constraints" ff V _group = LOG_GROUP_FEEDFORWARDS_CONSTRUCTION + contributing_devices = get_contributing_devices(model) + add_feedforward_constraints!(container, model, contributing_devices, ff) + end + return +end + function _add_feedforward_constraints!( container::OptimizationContainer, ::Type{T}, From 8083653ce4ddd8044c16bffccbd5852a3178ac74 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 18:44:47 -0600 Subject: [PATCH 209/370] implement interface constraints --- src/services_models/transmission_interface.jl | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/services_models/transmission_interface.jl b/src/services_models/transmission_interface.jl index a8c6edb350..add9e99104 100644 --- a/src/services_models/transmission_interface.jl +++ b/src/services_models/transmission_interface.jl @@ -17,3 +17,37 @@ function get_initial_conditions_service_model( ) where {T <: PSY.TransmissionInterface, D <: ConstantMaxInterfaceFlow} return ServiceModel(T, D) end + +function add_constraints!(container::OptimizationContainer, + ::Type{InterfaceFlowLimit}, + interface::T, + model::ServiceModel{T, ConstantMaxInterfaceFlow}, +) where {T <: PSY.TransmissionInterface} + expr = get_expression(container, InterfaceTotalFlow(), T) + interfaces, timesteps = axes(expr) + constraint_container_ub = lazy_container_addition!( + container, + InterfaceFlowLimit(), + T, + interfaces, + timesteps; + meta = "ub", + ) + constraint_container_lb = lazy_container_addition!( + container, + InterfaceFlowLimit(), + T, + interfaces, + timesteps; + meta = "lb", + ) + int_name = PSY.get_name(interface) + min_flow, max_flow = PSY.get_active_power_flow_limits(interface) + for t in timesteps + constraint_container_ub[int_name, t] = + JuMP.@constraint(get_jump_model(container), expr[int_name, t] <= max_flow) + constraint_container_lb[int_name, t] = + JuMP.@constraint(get_jump_model(container), expr[int_name, t] >= min_flow) + end + return +end From 517e11d646c61bf16898e55d4ac4c0ea426576cf Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 24 May 2023 13:09:21 -0600 Subject: [PATCH 210/370] update deps --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index ba7107aaa8..67bd074dd7 100644 --- a/Project.toml +++ b/Project.toml @@ -43,7 +43,7 @@ JuMP = "1" MathOptInterface = "1" PowerModels = "~0.19" PowerNetworkMatrices = "^0.7" -PowerSystems = "2" +PowerSystems = "^2.3" PrettyTables = "^1.3, 2" ProgressMeter = "^1.5" TimeSeries = "~0.23" From 7986c77afe71ffd7f8b7e78164a136cea4cdbf7d Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 14 Jun 2023 12:12:20 -0600 Subject: [PATCH 211/370] fix group reserves --- src/PowerSimulations.jl | 1 + src/services_models/agc.jl | 14 ++++++++++++++ src/services_models/reserve_group.jl | 11 +++++++++++ src/services_models/reserves.jl | 18 ++++++++++++++++-- test/test_basic_model_structs.jl | 4 ++-- 5 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 src/services_models/reserve_group.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 061d9aab5c..c774e5efa0 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -537,6 +537,7 @@ include("devices_models/devices/regulation_device.jl") # Services Models include("services_models/agc.jl") include("services_models/reserves.jl") +include("services_models/reserve_group.jl") include("services_models/transmission_interface.jl") include("services_models/group_reserve.jl") include("services_models/service_slacks.jl") diff --git a/src/services_models/agc.jl b/src/services_models/agc.jl index 3de0ddffdf..3ad04e7799 100644 --- a/src/services_models/agc.jl +++ b/src/services_models/agc.jl @@ -45,6 +45,20 @@ get_variable_multiplier(::SteadyStateFrequencyDeviation, d::PSY.AGC, ::AbstractA #! format: on +function get_default_time_series_names( + ::Type{PSY.AGC}, + ::Type{<:AbstractAGCFormulation}, +) + return Dict{Type{<:TimeSeriesParameter}, String}() +end + +function get_default_attributes( + ::Type{PSY.AGC}, + ::Type{<:AbstractAGCFormulation}, +) + return Dict{String, Any}() +end + """ Steady State deviation of the frequency """ diff --git a/src/services_models/reserve_group.jl b/src/services_models/reserve_group.jl new file mode 100644 index 0000000000..b64e1613a7 --- /dev/null +++ b/src/services_models/reserve_group.jl @@ -0,0 +1,11 @@ +function get_default_time_series_names( + ::Type{PSY.StaticReserveGroup{T}}, + ::Type{GroupReserve}) where {T <: PSY.ReserveDirection} + return Dict{String, Any}() +end + +function get_default_attributes( + ::Type{PSY.StaticReserveGroup{T}}, + ::Type{GroupReserve}) where {T <: PSY.ReserveDirection} + return Dict{String, Any}() +end diff --git a/src/services_models/reserves.jl b/src/services_models/reserves.jl index f02c13f619..f97ed1f2a1 100644 --- a/src/services_models/reserves.jl +++ b/src/services_models/reserves.jl @@ -41,6 +41,13 @@ function get_initial_conditions_service_model( return ServiceModel(T, D) end +function get_initial_conditions_service_model( + ::OperationModel, + ::ServiceModel{T, D}, +) where {T <: PSY.VariableReserveNonSpinning, D <: AbstractReservesFormulation} + return ServiceModel(T, D) +end + function get_default_time_series_names( ::Type{<:PSY.Reserve}, ::Type{T}, @@ -60,9 +67,9 @@ function get_default_time_series_names( end function get_default_time_series_names( - ::Type{<:PSY.Reserve}, + ::Type{T}, ::Type{<:AbstractReservesFormulation}, -) +) where {T <: PSY.Reserve} return Dict{Type{<:TimeSeriesParameter}, String}() end @@ -73,6 +80,13 @@ function get_default_attributes( return Dict{String, Any}() end +function get_default_attributes( + ::Type{<:PSY.ReserveNonSpinning}, + ::Type{<:AbstractReservesFormulation}, +) + return Dict{String, Any}() +end + ################################## Reserve Requirement Constraint ########################## function add_constraints!( container::OptimizationContainer, diff --git a/test/test_basic_model_structs.jl b/test/test_basic_model_structs.jl index 865705f8fa..6928b5e196 100644 --- a/test/test_basic_model_structs.jl +++ b/test/test_basic_model_structs.jl @@ -9,10 +9,10 @@ end end @testset "ServiceModel Tests" begin - @test_throws ArgumentError ServiceModel(AGC, PSI.AbstractServiceFormulation, "TestName") + @test_throws ArgumentError ServiceModel(AGC, PSI.AbstractAGCFormulation, "TestName") @test_throws ArgumentError ServiceModel( VariableReserve{PSY.ReserveUp}, - PSI.AbstractServiceFormulation, + PSI.AbstractReservesFormulation, "TestName2", ) end From 3616f89b474cddb6267c00ef88d5893da99f5335 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 22 May 2023 23:56:52 -0600 Subject: [PATCH 212/370] update constructors --- src/services_models/services_constructor.jl | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index fd478750fc..38c2c9f899 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -467,20 +467,19 @@ function construct_service!( container::OptimizationContainer, sys::PSY.System, ::ArgumentConstructStage, - model::ServiceModel{T, ConstantMaxInterfaceFlow}, + model::ServiceModel{SR, ConstantMaxInterfaceFlow}, devices_template::Dict{Symbol, DeviceModel}, incompatible_device_types::Set{<:DataType}, -) where {T <: PSY.TransmissionInterface} - # contributing_devices_map = get_contributing_devices_map(model) - interfaces = PSY.get_name.(get_available_components(T, sys)) - lazy_container_addition!( +) where {SR <: PSY.TransmissionInterface} + add_to_expression!( container, - InterfaceTotalFlow(), - T, - interfaces, - get_time_steps(container), + InterfaceTotalFlow, + FlowActivePowerVariable, + devices, + model, + network_model, ) - #add_feedforward_arguments!(container, model, service) + add_feedforward_arguments!(container, model, service) return end From 5fd471356f09886e8f20ece85185b2b2c8d1c615 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 00:23:51 -0600 Subject: [PATCH 213/370] more expression updates --- src/services_models/services_constructor.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index 38c2c9f899..9777c86037 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -471,13 +471,13 @@ function construct_service!( devices_template::Dict{Symbol, DeviceModel}, incompatible_device_types::Set{<:DataType}, ) where {SR <: PSY.TransmissionInterface} + contributing_devices = get_contributing_devices(model) add_to_expression!( container, InterfaceTotalFlow, FlowActivePowerVariable, - devices, + contributing_devices, model, - network_model, ) add_feedforward_arguments!(container, model, service) return From 0f738a87e0a07849f81c014828c8e635136e1af3 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 23 May 2023 18:44:25 -0600 Subject: [PATCH 214/370] add constructor methods for interfaces --- src/services_models/services_constructor.jl | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index 9777c86037..fd478750fc 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -467,19 +467,20 @@ function construct_service!( container::OptimizationContainer, sys::PSY.System, ::ArgumentConstructStage, - model::ServiceModel{SR, ConstantMaxInterfaceFlow}, + model::ServiceModel{T, ConstantMaxInterfaceFlow}, devices_template::Dict{Symbol, DeviceModel}, incompatible_device_types::Set{<:DataType}, -) where {SR <: PSY.TransmissionInterface} - contributing_devices = get_contributing_devices(model) - add_to_expression!( +) where {T <: PSY.TransmissionInterface} + # contributing_devices_map = get_contributing_devices_map(model) + interfaces = PSY.get_name.(get_available_components(T, sys)) + lazy_container_addition!( container, - InterfaceTotalFlow, - FlowActivePowerVariable, - contributing_devices, - model, + InterfaceTotalFlow(), + T, + interfaces, + get_time_steps(container), ) - add_feedforward_arguments!(container, model, service) + #add_feedforward_arguments!(container, model, service) return end From 1fae6fc3b8604cf3a6b9361f2f85a0f7694b9c06 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 15 Jun 2023 17:07:47 -0600 Subject: [PATCH 215/370] fix bug --- src/core/network_model.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/network_model.jl b/src/core/network_model.jl index 07b514fd76..923e9c735b 100644 --- a/src/core/network_model.jl +++ b/src/core/network_model.jl @@ -48,7 +48,7 @@ end get_use_slacks(m::NetworkModel) = m.use_slacks get_PTDF_matrix(m::NetworkModel) = m.PTDF_matrix get_duals(m::NetworkModel) = m.duals -get_network_formulation(::NetworkModel{T}) where {T <: PM.AbstractPowerModel} = T +get_network_formulation(::NetworkModel{T}) where {T} = T get_reference_buses(m::NetworkModel{T}) where {T <: PM.AbstractPowerModel} = collect(keys(m.subnetworks)) get_subnetworks(m::NetworkModel) = m.subnetworks From f15c4db4704de5e8b378bc7c2979f01def5def47 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 15 Jun 2023 17:07:53 -0600 Subject: [PATCH 216/370] add slacks for interface --- src/core/variables.jl | 6 +++ .../devices/common/add_to_expression.jl | 20 ++++++++++ src/services_models/services_constructor.jl | 40 +++++++++++++++++-- src/services_models/transmission_interface.jl | 32 +++++++++++++++ 4 files changed, 95 insertions(+), 3 deletions(-) diff --git a/src/core/variables.jl b/src/core/variables.jl index 852bed4ab8..da3d779a8b 100644 --- a/src/core/variables.jl +++ b/src/core/variables.jl @@ -213,6 +213,10 @@ struct HVDCFlowDirectionVariable <: VariableType end struct PieceWiseLinearCostVariable <: VariableType end +struct InterfaceFlowSlackUp <: VariableType end + +struct InterfaceFlowSlackDown <: VariableType end + const START_VARIABLES = (HotStartVariable, WarmStartVariable, ColdStartVariable) should_write_resulting_value(::Type{<:VariableType}) = true @@ -248,3 +252,5 @@ convert_result_to_natural_units(::Type{FlowActivePowerToFromVariable}) = true convert_result_to_natural_units(::Type{FlowReactivePowerFromToVariable}) = true convert_result_to_natural_units(::Type{FlowReactivePowerToFromVariable}) = true convert_result_to_natural_units(::Type{HVDCLosses}) = true +convert_result_to_natural_units(::Type{InterfaceFlowSlackUp}) = true +convert_result_to_natural_units(::Type{InterfaceFlowSlackDown}) = true diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 3b61b16f47..fb75c61de2 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -753,6 +753,26 @@ function add_to_expression!( return end +function add_to_expression!( + container::OptimizationContainer, + ::Type{InterfaceTotalFlow}, + ::Type{T}, + service::PSY.TransmissionInterface, + model::ServiceModel{PSY.TransmissionInterface, ConstantMaxInterfaceFlow}, +) where {T <: Union{InterfaceFlowSlackUp, InterfaceFlowSlackDown}} + expression = get_expression(container, InterfaceTotalFlow(), PSY.TransmissionInterface) + variable = get_variable(container, T(), PSY.TransmissionInterface) + service_name=PSY.get_name(service) + for t in get_time_steps(container) + _add_to_jump_expression!( + expression[service_name, t], + variable[service_name, t], + get_variable_multiplier(T(), service, ConstantMaxInterfaceFlow()), + ) + end + return +end + function add_to_expression!( container::OptimizationContainer, ::Type{InterfaceTotalFlow}, diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index fd478750fc..e46cb76a3f 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -471,13 +471,28 @@ function construct_service!( devices_template::Dict{Symbol, DeviceModel}, incompatible_device_types::Set{<:DataType}, ) where {T <: PSY.TransmissionInterface} - # contributing_devices_map = get_contributing_devices_map(model) - interfaces = PSY.get_name.(get_available_components(T, sys)) + interfaces = get_available_components(T, sys) + # Lazy container addition for the expressions. + if get_use_slacks(model) + add_variables!( + container, + InterfaceFlowSlackUp, + interfaces, + ConstantMaxInterfaceFlow() + ) + add_variables!( + container, + InterfaceFlowSlackDown, + interfaces, + ConstantMaxInterfaceFlow() + ) + end + lazy_container_addition!( container, InterfaceTotalFlow(), T, - interfaces, + PSY.get_name.(interfaces), get_time_steps(container), ) #add_feedforward_arguments!(container, model, service) @@ -502,8 +517,27 @@ function construct_service!( service, model, ) + + if get_use_slacks(model) + add_to_expression!( + container, + InterfaceTotalFlow, + InterfaceFlowSlackUp, + service, + model, + ) + add_to_expression!( + container, + InterfaceTotalFlow, + InterfaceFlowSlackDown, + service, + model, + ) + end + add_constraints!(container, InterfaceFlowLimit, service, model) add_feedforward_constraints!(container, model, service) add_constraint_dual!(container, sys, model) + objective_function!(container, service, model) return end diff --git a/src/services_models/transmission_interface.jl b/src/services_models/transmission_interface.jl index add9e99104..53643ce152 100644 --- a/src/services_models/transmission_interface.jl +++ b/src/services_models/transmission_interface.jl @@ -1,3 +1,12 @@ +#! format: off +get_variable_binary(_, ::Type{PSY.TransmissionInterface}, ::ConstantMaxInterfaceFlow) = false +get_variable_lower_bound(::InterfaceFlowSlackUp, ::PSY.TransmissionInterface, ::ConstantMaxInterfaceFlow) = 0.0 +get_variable_lower_bound(::InterfaceFlowSlackDown, ::PSY.TransmissionInterface, ::ConstantMaxInterfaceFlow) = 0.0 + +get_variable_multiplier(::InterfaceFlowSlackUp, ::PSY.TransmissionInterface, ::ConstantMaxInterfaceFlow) = 1.0 +get_variable_multiplier(::InterfaceFlowSlackDown, ::PSY.TransmissionInterface, ::ConstantMaxInterfaceFlow) = -1.0 + +#! format: On function get_default_time_series_names( ::Type{PSY.TransmissionInterface}, ::Type{ConstantMaxInterfaceFlow}, @@ -18,6 +27,8 @@ function get_initial_conditions_service_model( return ServiceModel(T, D) end + + function add_constraints!(container::OptimizationContainer, ::Type{InterfaceFlowLimit}, interface::T, @@ -51,3 +62,24 @@ function add_constraints!(container::OptimizationContainer, end return end + +function objective_function!( + container::OptimizationContainer, + service::T, + model::ServiceModel{T, U}, +) where {T <: PSY.TransmissionInterface, U <: ConstantMaxInterfaceFlow} + # At the moment the interfaces have no costs associated with them + if get_use_slacks(model) + variable_up = get_variable(container, InterfaceFlowSlackDown(), T) + variable_dn = get_variable(container, InterfaceFlowSlackDown(), T) + penalty = PSY.get_violation_penalty(service) + name = PSY.get_name(service) + for t in get_time_steps(container) + add_to_objective_invariant_expression!( + container, + (variable_dn[name, t] + variable_up[name, t]) * penalty, + ) + end + end + return +end From 00147b2217b51eab16cd28c46c8a01d5bfad415a Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 15 Jun 2023 17:09:35 -0600 Subject: [PATCH 217/370] formatter --- src/devices_models/devices/common/add_to_expression.jl | 2 +- src/services_models/services_constructor.jl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index fb75c61de2..f7cc493296 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -762,7 +762,7 @@ function add_to_expression!( ) where {T <: Union{InterfaceFlowSlackUp, InterfaceFlowSlackDown}} expression = get_expression(container, InterfaceTotalFlow(), PSY.TransmissionInterface) variable = get_variable(container, T(), PSY.TransmissionInterface) - service_name=PSY.get_name(service) + service_name = PSY.get_name(service) for t in get_time_steps(container) _add_to_jump_expression!( expression[service_name, t], diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index e46cb76a3f..c65a61d45f 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -478,13 +478,13 @@ function construct_service!( container, InterfaceFlowSlackUp, interfaces, - ConstantMaxInterfaceFlow() + ConstantMaxInterfaceFlow(), ) add_variables!( container, InterfaceFlowSlackDown, interfaces, - ConstantMaxInterfaceFlow() + ConstantMaxInterfaceFlow(), ) end From 38df327af2558680ae5232a54da58440e96205c2 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 14 Jul 2023 14:08:44 -0600 Subject: [PATCH 218/370] fix typo --- src/services_models/transmission_interface.jl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/services_models/transmission_interface.jl b/src/services_models/transmission_interface.jl index 53643ce152..13ae5a06b3 100644 --- a/src/services_models/transmission_interface.jl +++ b/src/services_models/transmission_interface.jl @@ -27,8 +27,6 @@ function get_initial_conditions_service_model( return ServiceModel(T, D) end - - function add_constraints!(container::OptimizationContainer, ::Type{InterfaceFlowLimit}, interface::T, @@ -70,7 +68,7 @@ function objective_function!( ) where {T <: PSY.TransmissionInterface, U <: ConstantMaxInterfaceFlow} # At the moment the interfaces have no costs associated with them if get_use_slacks(model) - variable_up = get_variable(container, InterfaceFlowSlackDown(), T) + variable_up = get_variable(container, InterfaceFlowSlackUp(), T) variable_dn = get_variable(container, InterfaceFlowSlackDown(), T) penalty = PSY.get_violation_penalty(service) name = PSY.get_name(service) From e4bf67d9eefd1e806c32e7a1f98aa6e596b19732 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 14 Jul 2023 16:57:01 -0600 Subject: [PATCH 219/370] fix initial condition model --- src/devices_models/devices/hydro_generation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 9773698f0e..f0399d91f1 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -66,7 +66,7 @@ function get_initial_conditions_device_model( ::OperationModel, ::DeviceModel{T, <:AbstractHydroFormulation}, ) where {T <: PSY.HydroGen} - return DeviceModel(T, HydroDispatchRunOfRiver) + return DeviceModel(T, HydroCommitmentRunOfRiver) end function get_default_time_series_names( From b2429641beade843e1bfd57e18fdecbbdc6766ba Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Mon, 17 Jul 2023 16:25:00 -0700 Subject: [PATCH 220/370] return energytargetparameter --- src/core/parameters.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index 9392294d80..45e39d2619 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -287,6 +287,9 @@ struct UpperBoundValueParameter <: VariableValueParameter end struct LowerBoundValueParameter <: VariableValueParameter end struct OnStatusParameter <: VariableValueParameter end struct EnergyLimitParameter <: VariableValueParameter end +# TODO: Check if EnergyTargetParameter and EnergyLimitParameter should be removed +# This affects feedforwards that can break if not defined +struct EnergyTargetParameter <: VariableValueParameter end struct FixValueParameter <: VariableValueParameter end struct CostFunctionParameter <: ObjectiveFunctionParameter end @@ -303,3 +306,6 @@ convert_result_to_natural_units(::Type{ReactivePowerTimeSeriesParameter}) = true convert_result_to_natural_units(::Type{RequirementTimeSeriesParameter}) = true convert_result_to_natural_units(::Type{UpperBoundValueParameter}) = true convert_result_to_natural_units(::Type{LowerBoundValueParameter}) = true +# TODO: Check if EnergyLimitParameter and EnergyTargetParameter should be removed +convert_result_to_natural_units(::Type{EnergyLimitParameter}) = true +convert_result_to_natural_units(::Type{EnergyTargetParameter}) = true \ No newline at end of file From 3f437b66364f6e1f59a652f50068cf82a2e13a7f Mon Sep 17 00:00:00 2001 From: Barrows Date: Wed, 19 Jul 2023 13:05:53 -0400 Subject: [PATCH 221/370] adding missing stuff --- docs/Project.toml | 1 + src/core/parameters.jl | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/docs/Project.toml b/docs/Project.toml index 93b8458786..db78f98971 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -6,6 +6,7 @@ DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" DocumenterTools = "35a29f4d-8980-5a13-9543-d66fff28ecb8" GLPK = "60bf3e95-4087-53dc-ae20-288a0d20c6a6" +HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b" InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1" Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" PowerSimulations = "e690365d-45e2-57bb-ac84-44ba829e73c4" diff --git a/src/core/parameters.jl b/src/core/parameters.jl index 2e7975a430..58aa0322a6 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -303,13 +303,40 @@ struct OutflowTimeSeriesParameter <: TimeSeriesParameter end abstract type VariableValueParameter <: RightHandSideParameter end +""" +Parameter to define variable upper bound +""" struct UpperBoundValueParameter <: VariableValueParameter end + +""" +Parameter to define variable lower bound +""" struct LowerBoundValueParameter <: VariableValueParameter end + +""" +Parameter to define unit commitment status +""" struct OnStatusParameter <: VariableValueParameter end + +""" +Parameter to define energy limit +""" struct EnergyLimitParameter <: VariableValueParameter end + +""" +Parameter to define fixed output values +""" struct FixValueParameter <: VariableValueParameter end + + +""" +Parameter to define energy storage target +""" struct EnergyTargetParameter <: VariableValueParameter end +""" +Parameter to define cost function coefficient +""" struct CostFunctionParameter <: ObjectiveFunctionParameter end abstract type AuxVariableValueParameter <: RightHandSideParameter end From 6e8ded666a794132fbce0ea2b280699948638ab8 Mon Sep 17 00:00:00 2001 From: Barrows Date: Wed, 19 Jul 2023 13:06:04 -0400 Subject: [PATCH 222/370] fixing hydro uc form --- docs/src/formulation_library/HydroGen.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md index efe13982b3..29704805f8 100644 --- a/docs/src/formulation_library/HydroGen.md +++ b/docs/src/formulation_library/HydroGen.md @@ -125,7 +125,7 @@ Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance ```math \begin{aligned} -& Pg_t \le Pg^\text{max}\\ +& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ & Pg_t - u_t Pg^\text{max} \le 0 \\ & Pg_t - u_t Pg^\text{min} \ge 0 \\ & Qg_t - u_t Qg^\text{max} \le 0 \\ From b896e54d63789a44a8c5f6cfbb9cdf0fb875e955 Mon Sep 17 00:00:00 2001 From: Clayton Barrows Date: Wed, 19 Jul 2023 13:39:49 -0400 Subject: [PATCH 223/370] Update src/core/parameters.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/core/parameters.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index 58aa0322a6..d20f0b40e4 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -328,7 +328,6 @@ Parameter to define fixed output values """ struct FixValueParameter <: VariableValueParameter end - """ Parameter to define energy storage target """ From 027ee8ea32fc009fe2fe51ca908f640357adb5d1 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 1 Aug 2023 18:34:21 -0600 Subject: [PATCH 224/370] remove duplicates with HyPS --- src/core/variables.jl | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/src/core/variables.jl b/src/core/variables.jl index da3d779a8b..2de603eda4 100644 --- a/src/core/variables.jl +++ b/src/core/variables.jl @@ -72,34 +72,6 @@ Docs abbreviation: ``E`` """ struct EnergyVariable <: VariableType end -""" -Struct to dispatch the creation of a variable for energy storage level (state of charge) of upper reservoir - -Docs abbreviation: ``E^{up}`` -""" -struct EnergyVariableUp <: VariableType end - -""" -Struct to dispatch the creation of a variable for energy storage level (state of charge) of lower reservoir - -Docs abbreviation: ``E^{down}`` -""" -struct EnergyVariableDown <: VariableType end - -""" -Struct to dispatch the creation of a slack variable for energy storage levels < target storage levels - -Docs abbreviation: ``E^{shortage}`` -""" -struct EnergyShortageVariable <: VariableType end - -""" -Struct to dispatch the creation of a slack variable for energy storage levels > target storage levels - -Docs abbreviation: ``E^{surplus}`` -""" -struct EnergySurplusVariable <: VariableType end - struct LiftVariable <: VariableType end """ From da20ae66bed5f3495940b373594ff4d545cd529b Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 1 Aug 2023 18:37:25 -0600 Subject: [PATCH 225/370] remove duplicates --- docs/src/api/PowerSimulations.md | 8 ----- src/PowerSimulations.jl | 4 --- src/core/variables.jl | 4 --- ...itial_conditions_update_in_memory_store.jl | 28 ------------------ .../initial_condition_update_simulation.jl | 29 ------------------- 5 files changed, 73 deletions(-) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index 2c935b8d8b..05ed08b86e 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -130,14 +130,6 @@ PowerAboveMinimumVariable ReservationVariable ``` -### Hydro Variables - -```@docs -WaterSpillageVariable -EnergyVariableUp -EnergyVariableDown -``` - ### Common for Hydro and Storage Variables ```@docs diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index c774e5efa0..baa7dd29cf 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -206,10 +206,6 @@ export HotStartVariable export WarmStartVariable export ColdStartVariable export EnergyVariable -export EnergyVariableUp -export EnergyVariableDown -export EnergyShortageVariable -export EnergySurplusVariable export LiftVariable export OnVariable export ReactivePowerVariable diff --git a/src/core/variables.jl b/src/core/variables.jl index 2de603eda4..7141f4ee6c 100644 --- a/src/core/variables.jl +++ b/src/core/variables.jl @@ -201,10 +201,6 @@ convert_result_to_natural_units(::Type{PowerAboveMinimumVariable}) = true convert_result_to_natural_units(::Type{ActivePowerInVariable}) = true convert_result_to_natural_units(::Type{ActivePowerOutVariable}) = true convert_result_to_natural_units(::Type{EnergyVariable}) = true -convert_result_to_natural_units(::Type{EnergyVariableUp}) = true -convert_result_to_natural_units(::Type{EnergyVariableDown}) = true -convert_result_to_natural_units(::Type{EnergyShortageVariable}) = true -convert_result_to_natural_units(::Type{EnergySurplusVariable}) = true convert_result_to_natural_units(::Type{ReactivePowerVariable}) = true convert_result_to_natural_units(::Type{ActivePowerReserveVariable}) = true convert_result_to_natural_units(::Type{ServiceRequirementVariable}) = true diff --git a/src/operation/initial_conditions_update_in_memory_store.jl b/src/operation/initial_conditions_update_in_memory_store.jl index b8767a273c..96e96a4f25 100644 --- a/src/operation/initial_conditions_update_in_memory_store.jl +++ b/src/operation/initial_conditions_update_in_memory_store.jl @@ -85,31 +85,3 @@ function update_initial_conditions!( end return end - -function update_initial_conditions!( - ics::Vector{T}, - store::EmulationModelStore, - ::Dates.Millisecond, -) where { - T <: InitialCondition{InitialEnergyLevelUp, S}, -} where {S <: Union{Float64, JuMP.VariableRef}} - for ic in ics - var_val = get_variable_value(store, EnergyVariableUp(), get_component_type(ic)) - set_ic_quantity!(ic, get_last_recorded_value(var_val)[get_component_name(ic)]) - end - return -end - -function update_initial_conditions!( - ics::Vector{T}, - store::EmulationModelStore, - ::Dates.Millisecond, -) where { - T <: InitialCondition{InitialEnergyLevelDown, S}, -} where {S <: Union{Float64, JuMP.VariableRef}} - for ic in ics - var_val = get_variable_value(store, EnergyVariableDown(), get_component_type(ic)) - set_ic_quantity!(ic, get_last_recorded_value(var_val)[get_component_name(ic)]) - end - return -end diff --git a/src/simulation/initial_condition_update_simulation.jl b/src/simulation/initial_condition_update_simulation.jl index 98df79210b..7d444cf609 100644 --- a/src/simulation/initial_condition_update_simulation.jl +++ b/src/simulation/initial_condition_update_simulation.jl @@ -141,32 +141,3 @@ function update_initial_conditions!( end return end - -function update_initial_conditions!( - ics::Vector{T}, - state::SimulationState, - ::Dates.Millisecond, -) where { - T <: InitialCondition{InitialEnergyLevelUp, S}, -} where {S <: Union{Float64, JuMP.VariableRef}} - for ic in ics - var_val = get_system_state_value(state, EnergyVariableUp(), get_component_type(ic)) - set_ic_quantity!(ic, var_val[get_component_name(ic)]) - end - return -end - -function update_initial_conditions!( - ics::Vector{T}, - state::SimulationState, - ::Dates.Millisecond, -) where { - T <: InitialCondition{InitialEnergyLevelDown, S}, -} where {S <: Union{Float64, JuMP.VariableRef}} - for ic in ics - var_val = - get_system_state_value(state, EnergyVariableDown(), get_component_type(ic)) - set_ic_quantity!(ic, var_val[get_component_name(ic)]) - end - return -end From 3b2660232f870c8ec171caf8a43251c67f74ea56 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 1 Aug 2023 22:31:16 -0600 Subject: [PATCH 226/370] remove some more duplicates --- docs/src/api/PowerSimulations.md | 2 -- .../devices/common/objective_functions.jl | 23 ------------------- .../devices/hydro_generation.jl | 4 ---- 3 files changed, 29 deletions(-) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index 05ed08b86e..6e082006fa 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -136,8 +136,6 @@ ReservationVariable ActivePowerOutVariable ActivePowerInVariable EnergyVariable -EnergyShortageVariable -EnergySurplusVariable ``` ### Branches and Network Variables diff --git a/src/devices_models/devices/common/objective_functions.jl b/src/devices_models/devices/common/objective_functions.jl index 87bf5faca2..52b56a17eb 100644 --- a/src/devices_models/devices/common/objective_functions.jl +++ b/src/devices_models/devices/common/objective_functions.jl @@ -76,29 +76,6 @@ function add_proportional_cost!( return end -function add_proportional_cost!( - container::OptimizationContainer, - ::U, - devices::IS.FlattenIteratorWrapper{T}, - ::V, -) where { - T <: PSY.Component, - U <: Union{EnergySurplusVariable, EnergyShortageVariable}, - V <: AbstractDeviceFormulation, -} - base_p = get_base_power(container) - multiplier = objective_function_multiplier(U(), V()) - for d in devices - op_cost_data = PSY.get_operation_cost(d) - cost_term = proportional_cost(op_cost_data, U(), d, V()) - iszero(cost_term) && continue - for t in get_time_steps(container) - _add_proportional_term!(container, U(), d, cost_term * multiplier * base_p, t) - end - end - return -end - function add_proportional_cost!( container::OptimizationContainer, ::U, diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 69e861b2c7..95cd47efec 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -48,14 +48,10 @@ initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::Abstract ########################Objective Function################################################## proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergySurplusVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_surplus_cost(cost) -proportional_cost(cost::PSY.StorageManagementCost, ::EnergyShortageVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_energy_shortage_cost(cost) objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::EnergySurplusVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_NEGATIVE -objective_function_multiplier(::EnergyShortageVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE From 308ca0a8d2b439140b7116283d1ee1ed8a20e938 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 1 Aug 2023 23:24:23 -0600 Subject: [PATCH 227/370] remove unused ic's --- src/core/initial_conditions.jl | 2 -- src/initial_conditions/add_initial_condition.jl | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/core/initial_conditions.jl b/src/core/initial_conditions.jl index e1ba803d08..59a2fdc68a 100644 --- a/src/core/initial_conditions.jl +++ b/src/core/initial_conditions.jl @@ -158,6 +158,4 @@ struct DeviceStatus <: InitialConditionType end struct InitialTimeDurationOn <: InitialConditionType end struct InitialTimeDurationOff <: InitialConditionType end struct InitialEnergyLevel <: InitialConditionType end -struct InitialEnergyLevelUp <: InitialConditionType end -struct InitialEnergyLevelDown <: InitialConditionType end struct AreaControlError <: InitialConditionType end diff --git a/src/initial_conditions/add_initial_condition.jl b/src/initial_conditions/add_initial_condition.jl index ebc83377a3..5dd0dba455 100644 --- a/src/initial_conditions/add_initial_condition.jl +++ b/src/initial_conditions/add_initial_condition.jl @@ -162,7 +162,7 @@ function _get_initial_conditions_value( T <: InitialCondition{U, JuMP.VariableRef}, V <: Union{AbstractDeviceFormulation, AbstractServiceFormulation}, W <: PSY.Component, -} where {U <: Union{InitialEnergyLevel, InitialEnergyLevelUp, InitialEnergyLevelDown}} +} where {U <: InitialEnergyLevel} var_type = initial_condition_variable(U(), component, V()) val = initial_condition_default(U(), component, V()) @debug "Device $(PSY.get_name(component)) initialized DeviceStatus as $var_type" _group = @@ -180,7 +180,7 @@ function _get_initial_conditions_value( T <: InitialCondition{U, Float64}, V <: Union{AbstractDeviceFormulation, AbstractServiceFormulation}, W <: PSY.Component, -} where {U <: Union{InitialEnergyLevel, InitialEnergyLevelUp, InitialEnergyLevelDown}} +} where {U <: InitialEnergyLevel} var_type = initial_condition_variable(U(), component, V()) val = initial_condition_default(U(), component, V()) @debug "Device $(PSY.get_name(component)) initialized DeviceStatus as $var_type" _group = From 01a56ce43e9ec8189bb3f3b1554b8529dce1c07d Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 2 Aug 2023 00:00:02 -0600 Subject: [PATCH 228/370] remove undefined variable --- src/feedforward/feedforward_arguments.jl | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/feedforward/feedforward_arguments.jl b/src/feedforward/feedforward_arguments.jl index 33d62e15b7..adad3f4a18 100644 --- a/src/feedforward/feedforward_arguments.jl +++ b/src/feedforward/feedforward_arguments.jl @@ -69,16 +69,3 @@ function _add_feedforward_arguments!( ) return end - -function _add_feedforward_arguments!( - container::OptimizationContainer, - model::DeviceModel, - devices::IS.FlattenIteratorWrapper{T}, - ff::EnergyTargetFeedforward, -) where {T <: PSY.Component} - parameter_type = get_default_parameter_type(ff, T) - add_parameters!(container, parameter_type, ff, model, devices) - # Enabling this FF requires the addition of an extra variable - add_variables!(container, EnergyShortageVariable, devices, get_formulation(model)()) - return -end From 7f3f59ec6bb0bb4e3268c35fbfab237ddbcc9ce2 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 2 Aug 2023 21:40:07 -0600 Subject: [PATCH 229/370] fix interface slacks --- src/core/optimization_container.jl | 5 +-- .../devices/common/add_to_expression.jl | 4 +-- src/services_models/reserves.jl | 4 +-- src/services_models/service_slacks.jl | 35 ++++++++++++++++++- src/services_models/services_constructor.jl | 19 +++------- src/services_models/transmission_interface.jl | 12 ------- 6 files changed, 46 insertions(+), 33 deletions(-) diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index 08130009f5..dd58ca8ccb 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -1687,11 +1687,12 @@ function lazy_container_addition!( axs...; kwargs..., ) where {T <: ConstraintType, U <: Union{PSY.Component, PSY.System}} - if !has_container_key(container, T, U) + meta = get(kwargs, :meta, CONTAINER_KEY_EMPTY_META) + if !has_container_key(container, T, U, meta) cons_container = add_constraints_container!(container, constraint, U, axs...; kwargs...) else - cons_container = get_constraint(container, constraint, U) + cons_container = get_constraint(container, constraint, U, meta) end return cons_container end diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index f7cc493296..9ba446b447 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -761,12 +761,12 @@ function add_to_expression!( model::ServiceModel{PSY.TransmissionInterface, ConstantMaxInterfaceFlow}, ) where {T <: Union{InterfaceFlowSlackUp, InterfaceFlowSlackDown}} expression = get_expression(container, InterfaceTotalFlow(), PSY.TransmissionInterface) - variable = get_variable(container, T(), PSY.TransmissionInterface) service_name = PSY.get_name(service) + variable = get_variable(container, T(), PSY.TransmissionInterface, service_name) for t in get_time_steps(container) _add_to_jump_expression!( expression[service_name, t], - variable[service_name, t], + variable[t], get_variable_multiplier(T(), service, ConstantMaxInterfaceFlow()), ) end diff --git a/src/services_models/reserves.jl b/src/services_models/reserves.jl index f97ed1f2a1..5b54896495 100644 --- a/src/services_models/reserves.jl +++ b/src/services_models/reserves.jl @@ -118,7 +118,7 @@ function add_constraints!( ts_vector = get_time_series(container, service, "requirement") - use_slacks && (slack_vars = reserve_slacks(container, service)) + use_slacks && (slack_vars = reserve_slacks!(container, service)) requirement = PSY.get_requirement(service) jump_model = get_jump_model(container) if parameters @@ -175,7 +175,7 @@ function add_constraints!( reserve_variable = get_variable(container, ActivePowerReserveVariable(), SR, service_name) use_slacks = get_use_slacks(model) - use_slacks && (slack_vars = reserve_slacks(container, service)) + use_slacks && (slack_vars = reserve_slacks!(container, service)) requirement = PSY.get_requirement(service) jump_model = get_jump_model(container) diff --git a/src/services_models/service_slacks.jl b/src/services_models/service_slacks.jl index 1c6adafa35..0ec2464fda 100644 --- a/src/services_models/service_slacks.jl +++ b/src/services_models/service_slacks.jl @@ -1,4 +1,4 @@ -function reserve_slacks( +function reserve_slacks!( container::OptimizationContainer, service::T, ) where {T <: PSY.Reserve} @@ -21,3 +21,36 @@ function reserve_slacks( end return variable end + +function transmission_interface_slacks!( + container::OptimizationContainer, + service::T, +) where {T <: PSY.TransmissionInterface} + time_steps = get_time_steps(container) + + for variable_type in [InterfaceFlowSlackUp, InterfaceFlowSlackDown] + variable = add_variable_container!( + container, + variable_type(), + T, + PSY.get_name(service), + time_steps, + ) + penalty = PSY.get_violation_penalty(service) + name = PSY.get_name(service) + for t in time_steps + variable[t] = JuMP.@variable( + get_jump_model(container), + base_name = "$(T)_$(variable_type)_{$(name), $(t)}", + ) + JuMP.set_lower_bound(variable[t], 0.0) + + add_to_objective_invariant_expression!( + container, + variable[t] * penalty, + ) + end + end + + return +end diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index c65a61d45f..4955ba66a9 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -472,22 +472,13 @@ function construct_service!( incompatible_device_types::Set{<:DataType}, ) where {T <: PSY.TransmissionInterface} interfaces = get_available_components(T, sys) - # Lazy container addition for the expressions. if get_use_slacks(model) - add_variables!( - container, - InterfaceFlowSlackUp, - interfaces, - ConstantMaxInterfaceFlow(), - ) - add_variables!( - container, - InterfaceFlowSlackDown, - interfaces, - ConstantMaxInterfaceFlow(), - ) + # Adding the slacks can be done in a cleaner fashion + interface = PSY.get_component(T, sys, get_service_name(model)) + @assert PSY.get_available(interface) + transmission_interface_slacks!(container, interface) end - + # Lazy container addition for the expressions. lazy_container_addition!( container, InterfaceTotalFlow(), diff --git a/src/services_models/transmission_interface.jl b/src/services_models/transmission_interface.jl index 13ae5a06b3..25c2e550eb 100644 --- a/src/services_models/transmission_interface.jl +++ b/src/services_models/transmission_interface.jl @@ -67,17 +67,5 @@ function objective_function!( model::ServiceModel{T, U}, ) where {T <: PSY.TransmissionInterface, U <: ConstantMaxInterfaceFlow} # At the moment the interfaces have no costs associated with them - if get_use_slacks(model) - variable_up = get_variable(container, InterfaceFlowSlackUp(), T) - variable_dn = get_variable(container, InterfaceFlowSlackDown(), T) - penalty = PSY.get_violation_penalty(service) - name = PSY.get_name(service) - for t in get_time_steps(container) - add_to_objective_invariant_expression!( - container, - (variable_dn[name, t] + variable_up[name, t]) * penalty, - ) - end - end return end From f35f4d1617eccc4b004908aee63d7343afa5130c Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 2 Aug 2023 22:32:47 -0600 Subject: [PATCH 230/370] small improvement to the progress bar --- src/simulation/simulation.jl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/simulation/simulation.jl b/src/simulation/simulation.jl index e9869c3525..2cd14d7a4a 100644 --- a/src/simulation/simulation.jl +++ b/src/simulation/simulation.jl @@ -858,6 +858,16 @@ function _execute!( step, "start", ) + # This progress print is required to show the progress bar upfront + ProgressMeter.update!( + prog_bar, + 1; + showvalues = [ + (:Step, 1), + (:Problem, get_name(get_simulation_model(models, 1))), + (:("Simulation Timestamp"), get_current_time(sim)), + ], + ) for (ix, model_number) in enumerate(execution_order) model = get_simulation_model(models, model_number) model_name = get_name(model) From 88820b54e659163a1a0b13998c993258051dca71 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 3 Aug 2023 22:34:42 -0600 Subject: [PATCH 231/370] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 67bd074dd7..6850331f23 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "PowerSimulations" uuid = "e690365d-45e2-57bb-ac84-44ba829e73c4" authors = ["Jose Daniel Lara", "Clayton Barrows", "Daniel Thom", "Dheepak Krishnamurthy", "Sourabh Dalvi"] -version = "0.20.3" +version = "0.21.0" [deps] CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" From 8af9b4a9d5e88a848dcd12efa8b928a470d6f812 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 4 Aug 2023 13:28:58 -0600 Subject: [PATCH 232/370] add lower_bound to on variable based on must run --- src/devices_models/devices/thermal_generation.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index 3e8b333652..fce4d42a87 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -33,7 +33,8 @@ get_variable_upper_bound(::ReactivePowerVariable, d::PSY.ThermalGen, ::AbstractT ############## OnVariable, ThermalGen #################### get_variable_binary(::OnVariable, ::Type{<:PSY.ThermalGen}, ::AbstractThermalFormulation) = true -get_variable_warm_start_value(::OnVariable, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_status(d) ? 1.0 : 0.0 +get_variable_warm_start_value(::OnVariable, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_status(d) ? 1.0 : 0.0 +get_variable_lower_bound(::ActivePowerVariable, d::PSY.ThermalGen, ::AbstractThermalUnitCommitment) = PSY.get_must_run(d) ? 1.0 : 0.0 ############## StopVariable, ThermalGen #################### get_variable_binary(::StopVariable, ::Type{<:PSY.ThermalGen}, ::AbstractThermalFormulation) = true From 145c83ce664b86011e5d0b5cefff00e47ff91e75 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 4 Aug 2023 13:34:43 -0600 Subject: [PATCH 233/370] remove duplicate constraint --- docs/src/api/PowerSimulations.md | 1 - src/PowerSimulations.jl | 1 - src/core/constraints.jl | 1 - .../thermalgeneration_constructor.jl | 2 -- .../devices/thermal_generation.jl | 22 ------------------- ..._device_thermal_generation_constructors.jl | 2 -- test/test_utils/model_checks.jl | 17 -------------- 7 files changed, 46 deletions(-) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index 6e082006fa..6440195532 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -223,7 +223,6 @@ ReservePowerConstraint ActiveRangeICConstraint CommitmentConstraint DurationConstraint -MustRunConstraint RampConstraint RampLimitConstraint StartupInitialConditionConstraint diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index baa7dd29cf..f95ca452c1 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -285,7 +285,6 @@ export InflowRangeConstraint export InputActivePowerVariableLimitsConstraint export InputPowerRangeConstraint export InterConnectionLimitConstraint -export MustRunConstraint export NetworkFlowConstraint export NodalBalanceActiveConstraint export NodalBalanceReactiveConstraint diff --git a/src/core/constraints.jl b/src/core/constraints.jl index 7e0af2ef48..02d0dbaae3 100644 --- a/src/core/constraints.jl +++ b/src/core/constraints.jl @@ -66,7 +66,6 @@ struct FrequencyResponseConstraint <: ConstraintType end struct InflowRangeConstraint <: ConstraintType end #not being used struct InputPowerRangeConstraint <: ConstraintType end #not being used struct InterConnectionLimitConstraint <: ConstraintType end #not being used -struct MustRunConstraint <: ConstraintType end struct NetworkFlowConstraint <: ConstraintType end struct NodalBalanceActiveConstraint <: ConstraintType end struct NodalBalanceReactiveConstraint <: ConstraintType end diff --git a/src/devices_models/device_constructors/thermalgeneration_constructor.jl b/src/devices_models/device_constructors/thermalgeneration_constructor.jl index 06a3dee262..59f1c6083d 100644 --- a/src/devices_models/device_constructors/thermalgeneration_constructor.jl +++ b/src/devices_models/device_constructors/thermalgeneration_constructor.jl @@ -969,7 +969,6 @@ function construct_device!( model, network_model, ) - add_constraints!(container, MustRunConstraint, devices, model, network_model) add_constraints!(container, ActiveRangeICConstraint, devices, model, network_model) add_feedforward_constraints!(container, model, devices) @@ -1091,7 +1090,6 @@ function construct_device!( model, network_model, ) - add_constraints!(container, MustRunConstraint, devices, model, network_model) add_constraints!(container, ActiveRangeICConstraint, devices, model, network_model) add_feedforward_constraints!(container, model, devices) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index fce4d42a87..cd216936ca 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -1194,28 +1194,6 @@ function add_constraints!( return end -""" -This function creates constraints that keep must run devices online -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{MustRunConstraint}, - devices::IS.FlattenIteratorWrapper{T}, - model::DeviceModel{T, S}, - ::NetworkModel{<:PM.AbstractPowerModel}, -) where {T <: PSY.ThermalGen, S <: AbstractThermalUnitCommitment} - time_steps = get_time_steps(container) - varon = get_variable(container, OnVariable(), T) - names = [PSY.get_name(d) for d in devices if PSY.get_must_run(d)] - constraint = - add_constraints_container!(container, MustRunConstraint(), T, names, time_steps) - - for name in names, t in time_steps - constraint[name, t] = JuMP.@constraint(container.JuMPmodel, varon[name, t] >= 1.0) - end - return -end - ########################### time duration constraints ###################################### """ If the fraction of hours that a generator has a duration constraint is less than diff --git a/test/test_device_thermal_generation_constructors.jl b/test/test_device_thermal_generation_constructors.jl index 6bf49d05d3..ae77e6e3a1 100644 --- a/test/test_device_thermal_generation_constructors.jl +++ b/test/test_device_thermal_generation_constructors.jl @@ -397,7 +397,6 @@ end constraint_keys = [ PSI.ConstraintKey(ActiveRangeICConstraint, PSY.ThermalMultiStart), PSI.ConstraintKey(StartTypeConstraint, PSY.ThermalMultiStart), - PSI.ConstraintKey(MustRunConstraint, PSY.ThermalMultiStart), PSI.ConstraintKey( StartupTimeLimitTemperatureConstraint, PSY.ThermalMultiStart, @@ -425,7 +424,6 @@ end constraint_keys = [ PSI.ConstraintKey(ActiveRangeICConstraint, PSY.ThermalMultiStart), PSI.ConstraintKey(StartTypeConstraint, PSY.ThermalMultiStart), - PSI.ConstraintKey(MustRunConstraint, PSY.ThermalMultiStart), PSI.ConstraintKey( StartupTimeLimitTemperatureConstraint, PSY.ThermalMultiStart, diff --git a/test/test_utils/model_checks.jl b/test/test_utils/model_checks.jl index 058a4ea1d4..fc4bda9d82 100644 --- a/test/test_utils/model_checks.jl +++ b/test/test_utils/model_checks.jl @@ -498,20 +498,3 @@ function check_constraint_count( filter_func = x -> x.name in set_name, ) end - -function check_constraint_count( - model, - ::PSI.MustRunConstraint, - ::Type{T}, -) where {T <: PSY.Component} - container = PSI.get_optimization_container(model) - _devices = - filter!(x -> x.must_run, collect(get_components(PSY.get_available, T, model.sys))) - set_name = PSY.get_name.(_devices) - return check_constraint_count( - model, - PSI.MustRunConstraint(), - T; - filter_func = x -> x.name in set_name, - ) -end From 93979035b9ae4501bc52b0d92adf6d66635c05ff Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 4 Aug 2023 13:36:08 -0600 Subject: [PATCH 234/370] type corrections --- src/devices_models/devices/thermal_generation.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index cd216936ca..b41f63bc1a 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -265,7 +265,7 @@ Min and max active power limits for multi-start unit commitment formulations function get_min_max_limits( device, ::Type{ActivePowerVariableLimitsConstraint}, - ::Type{<:ThermalMultiStartUnitCommitment}, + ::Type{ThermalMultiStartUnitCommitment}, ) # -> Union{Nothing, NamedTuple{(:startup, :shutdown), Tuple{Float64, Float64}}} return ( min = 0.0, @@ -281,7 +281,7 @@ function add_variable!( container::OptimizationContainer, variable_type::T, devices::U, - formulation, + formulation::AbstractThermalFormulation, ) where { T <: OnVariable, U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, From 6628d69a127cd5ea6484dab770aebcda0ed985eb Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 4 Aug 2023 13:36:44 -0600 Subject: [PATCH 235/370] use force=true in must_run fix --- src/devices_models/devices/thermal_generation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index b41f63bc1a..c8d31e4382 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -311,7 +311,7 @@ function add_variable!( init !== nothing && JuMP.set_start_value(variable[name, t], init) end if PSY.get_must_run(d) - JuMP.fix(variable[name, t], 1.0) + JuMP.fix(variable[name, t], 1.0; force=true) end end From 76b80072e7c768a359731f1daa04d4cf0364ff8d Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 7 Aug 2023 10:45:22 -0600 Subject: [PATCH 236/370] formatter --- src/devices_models/devices/thermal_generation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index c8d31e4382..bafed666f6 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -311,7 +311,7 @@ function add_variable!( init !== nothing && JuMP.set_start_value(variable[name, t], init) end if PSY.get_must_run(d) - JuMP.fix(variable[name, t], 1.0; force=true) + JuMP.fix(variable[name, t], 1.0; force = true) end end From d351fb786058c679f52dad4ff370aae44d6e7f12 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 7 Aug 2023 11:04:11 -0600 Subject: [PATCH 237/370] remove unused functions --- src/PowerSimulations.jl | 1 - src/core/constraints.jl | 1 - src/feedforward/feedforward_constraints.jl | 67 ---------------------- 3 files changed, 69 deletions(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index f95ca452c1..7f111dd8c5 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -259,7 +259,6 @@ export EnergyCapacityConstraint export EnergyCapacityDownConstraint export EnergyCapacityUpConstraint export EnergyLimitConstraint -export EnergyShortageVariableLimitsConstraint export EnergyTargetConstraint export EqualityConstraint export FeedforwardSemiContinousConstraint diff --git a/src/core/constraints.jl b/src/core/constraints.jl index 02d0dbaae3..1771a0b784 100644 --- a/src/core/constraints.jl +++ b/src/core/constraints.jl @@ -42,7 +42,6 @@ struct EnergyCapacityDownConstraint <: ConstraintType end struct EnergyCapacityUpConstraint <: ConstraintType end struct EnergyLimitConstraint <: ConstraintType end # not being used struct EnergyTargetConstraint <: ConstraintType end -struct EnergyShortageVariableLimitsConstraint <: ConstraintType end # not being used struct EqualityConstraint <: ConstraintType end struct FeedforwardSemiContinousConstraint <: ConstraintType end struct FeedforwardIntegralLimitConstraint <: ConstraintType end diff --git a/src/feedforward/feedforward_constraints.jl b/src/feedforward/feedforward_constraints.jl index ee676f288d..3c31c8e6bc 100644 --- a/src/feedforward/feedforward_constraints.jl +++ b/src/feedforward/feedforward_constraints.jl @@ -537,70 +537,3 @@ function add_feedforward_constraints!( end return end - -@doc raw""" - add_feedforward_constraints( - container::OptimizationContainer, - ::DeviceModel, - devices::IS.FlattenIteratorWrapper{T}, - ff::EnergyTargetFeedforward, - ) where {T <: PSY.Component} - -Constructs a equality constraint to a fix a variable in one model using the variable value from other model results. - - -``` variable[var_name, t] + slack[var_name, t] >= param[var_name, t] ``` - -# LaTeX - -`` x + slack >= param`` - -# Arguments -* container::OptimizationContainer : the optimization_container model built in PowerSimulations -* model::DeviceModel : the device model -* devices::IS.FlattenIteratorWrapper{T} : list of devices -* ff::EnergyTargetFeedforward : a instance of the FixValue Feedforward -""" -function add_feedforward_constraints!( - container::OptimizationContainer, - ::DeviceModel, - devices::IS.FlattenIteratorWrapper{T}, - ff::EnergyTargetFeedforward, -) where {T <: PSY.Component} - time_steps = get_time_steps(container) - parameter_type = get_default_parameter_type(ff, T) - param = get_parameter_array(container, parameter_type(), T) - multiplier = get_parameter_multiplier_array(container, parameter_type(), T) - target_period = ff.target_period - penalty_cost = ff.penalty_cost - for var in get_affected_values(ff) - variable = get_variable(container, var) - slack_var = get_variable(container, EnergyShortageVariable(), T) - set_name, set_time = JuMP.axes(variable) - IS.@assert_op set_name == [PSY.get_name(d) for d in devices] - IS.@assert_op set_time == time_steps - - var_type = get_entry_type(var) - con_ub = add_constraints_container!( - container, - FeedforwardEnergyTargetConstraint(), - T, - set_name; - meta = "$(var_type)target", - ) - - for d in devices - name = PSY.get_name(d) - con_ub[name] = JuMP.@constraint( - container.JuMPmodel, - variable[name, target_period] + slack_var[name, target_period] >= - param[name, target_period] * multiplier[name, target_period] - ) - add_to_objective_invariant_expression!( - container, - slack_var[name, target_period] * penalty_cost, - ) - end - end - return -end From edd4a80d7351d0c60b9ba6a7235566a9ef3a9201 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 7 Aug 2023 13:39:39 -0600 Subject: [PATCH 238/370] Bump version --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 6850331f23..1244af2cb0 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "PowerSimulations" uuid = "e690365d-45e2-57bb-ac84-44ba829e73c4" authors = ["Jose Daniel Lara", "Clayton Barrows", "Daniel Thom", "Dheepak Krishnamurthy", "Sourabh Dalvi"] -version = "0.21.0" +version = "0.21.1" [deps] CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" From 21f6dff464b322f4785a426ef6dd215082ed0510 Mon Sep 17 00:00:00 2001 From: Daniel Thom Date: Tue, 27 Jun 2023 11:35:56 -0600 Subject: [PATCH 239/370] Refactor storage and access of results This commit changes storage and access of results in order to improve performance. DataFrames are replaced by DenseAxisArrays. It also optimizes the generation of realized results. --- src/PowerSimulations.jl | 11 +- src/core/dataset.jl | 81 ++-- src/core/dataset_container.jl | 11 +- src/core/optimization_container.jl | 12 +- src/core/results_by_time.jl | 84 ++++ src/core/store_common.jl | 26 +- src/operation/abstract_model_store.jl | 9 - src/operation/decision_model.jl | 2 +- src/operation/decision_model_store.jl | 76 ++-- src/operation/emulation_model.jl | 2 +- src/operation/emulation_model_store.jl | 53 ++- src/operation/operation_model_interface.jl | 27 +- src/operation/problem_results.jl | 107 ++--- src/parameters/update_parameters.jl | 42 +- .../decision_model_simulation_results.jl | 424 +++++++++--------- .../emulation_model_simulation_results.jl | 281 ++++-------- src/simulation/hdf_simulation_store.jl | 47 +- src/simulation/in_memory_simulation_store.jl | 48 +- src/simulation/realized_meta.jl | 47 +- src/simulation/simulation.jl | 2 +- src/simulation/simulation_problem_results.jl | 134 +++--- src/simulation/simulation_results.jl | 4 - src/simulation/simulation_state.jl | 69 +-- src/utils/dataframes_utils.jl | 8 +- src/utils/jump_utils.jl | 42 +- test/test_simulation_build.jl | 4 +- test/test_simulation_results.jl | 29 +- test/test_utils.jl | 14 +- 28 files changed, 825 insertions(+), 871 deletions(-) create mode 100644 src/core/results_by_time.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 7f111dd8c5..2fc2a5b2b6 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -452,6 +452,7 @@ include("core/cache_utils.jl") include("core/optimizer_stats.jl") include("core/dataset.jl") include("core/dataset_container.jl") +include("core/results_by_time.jl") include("core/optimization_container.jl") include("core/store_common.jl") @@ -496,9 +497,9 @@ include("simulation/simulation_store_params.jl") include("simulation/hdf_simulation_store.jl") include("simulation/in_memory_simulation_store.jl") include("simulation/simulation_problem_results.jl") -include("simulation/realized_meta.jl") include("simulation/decision_model_simulation_results.jl") include("simulation/emulation_model_simulation_results.jl") +include("simulation/realized_meta.jl") include("simulation/simulation_partitions.jl") include("simulation/simulation_partition_results.jl") include("simulation/simulation_sequence.jl") @@ -575,4 +576,12 @@ include("utils/recorder_events.jl") include("utils/datetime_utils.jl") include("utils/generate_valid_formulations.jl") +# TODO: These exist for backward compatibility and need to be deprecated and removed. +read_aux_variables_with_keys(args...; kwargs...) = + read_results_with_keys(args...; kwargs...) +read_duals_with_keys(args...; kwargs...) = read_results_with_keys(args...; kwargs...) +read_expressions_with_keys(args...; kwargs...) = read_results_with_keys(args...; kwargs...) +read_parameters_with_keys(args...; kwargs...) = read_results_with_keys(args...; kwargs...) +read_variables_with_keys(args...; kwargs...) = read_results_with_keys(args...; kwargs...) + end diff --git a/src/core/dataset.jl b/src/core/dataset.jl index 4d18d923c9..be87fb6fc4 100644 --- a/src/core/dataset.jl +++ b/src/core/dataset.jl @@ -1,6 +1,5 @@ abstract type AbstractDataset end -Base.length(s::AbstractDataset) = size(s.values)[1] get_data_resolution(s::AbstractDataset)::Dates.Millisecond = s.resolution get_last_recorded_row(s::AbstractDataset) = s.last_recorded_row @@ -21,8 +20,9 @@ end # Values field is accessed with dot syntax to avoid type instability -mutable struct DataFrameDataset <: AbstractDataset - values::DataFrames.DataFrame +mutable struct InMemoryDataset <: AbstractDataset + "Data with dimensions (column names, row indexes)" + values::DenseAxisArray{Float64, 2} # We use Array here to allow for overwrites when updating the state timestamps::Vector{Dates.DateTime} # Resolution is needed because AbstractDataset might have just one row @@ -32,13 +32,13 @@ mutable struct DataFrameDataset <: AbstractDataset update_timestamp::Dates.DateTime end -function DataFrameDataset( - values::DataFrames.DataFrame, +function InMemoryDataset( + values::DenseAxisArray{Float64, 2}, timestamps::Vector{Dates.DateTime}, resolution::Dates.Millisecond, end_of_step_index::Int, ) - return DataFrameDataset( + return InMemoryDataset( values, timestamps, resolution, @@ -48,8 +48,8 @@ function DataFrameDataset( ) end -function DataFrameDataset(values::DataFrames.DataFrame) - return DataFrameDataset( +function InMemoryDataset(values::DenseAxisArray{Float64, 2}) + return InMemoryDataset( values, Vector{Dates.DateTime}(), Dates.Second(0.0), @@ -59,41 +59,42 @@ function DataFrameDataset(values::DataFrames.DataFrame) ) end +Base.length(s::InMemoryDataset) = size(s.values)[2] + function make_system_state( - values::DataFrames.DataFrame, + values::DenseAxisArray{Float64, 2}, timestamp::Dates.DateTime, resolution::Dates.Millisecond, ) - return DataFrameDataset(values, [timestamp], resolution, 0, 1, UNSET_INI_TIME) + return InMemoryDataset(values, [timestamp], resolution, 0, 1, UNSET_INI_TIME) end -function get_dataset_value(s::DataFrameDataset, date::Dates.DateTime) +function get_dataset_value(s::InMemoryDataset, date::Dates.DateTime) s_index = find_timestamp_index(s.timestamps, date) if isnothing(s_index) error("Request time stamp $date not in the state") end - return s.values[s_index, :] + return s.values[:, s_index] end -function get_column_names(::OptimizationContainerKey, s::DataFrameDataset) - return DataFrames.names(s.values) -end +get_column_names(s::InMemoryDataset) = axes(s.values)[1] +get_column_names(::OptimizationContainerKey, s::InMemoryDataset) = get_column_names(s) -function get_last_recorded_value(s::DataFrameDataset) +function get_last_recorded_value(s::InMemoryDataset) if get_last_recorded_row(s) == 0 error("The Dataset hasn't been written yet") end - return s.values[get_last_recorded_row(s), :] + return s.values[:, get_last_recorded_row(s)] end -function get_end_of_step_timestamp(s::DataFrameDataset) +function get_end_of_step_timestamp(s::InMemoryDataset) return s.timestamps[s.end_of_step_index] end """ Return the timestamp from most recent data row updated in the dataset. This value may not be the same as the result from `get_update_timestamp` """ -function get_last_updated_timestamp(s::DataFrameDataset) +function get_last_updated_timestamp(s::InMemoryDataset) last_recorded_row = get_last_recorded_row(s) if last_recorded_row == 0 return UNSET_INI_TIME @@ -101,7 +102,7 @@ function get_last_updated_timestamp(s::DataFrameDataset) return s.timestamps[last_recorded_row] end -function get_value_timestamp(s::DataFrameDataset, date::Dates.DateTime) +function get_value_timestamp(s::InMemoryDataset, date::Dates.DateTime) s_index = find_timestamp_index(s.timestamps, date) if isnothing(s_index) error("Request time stamp $date not in the state") @@ -109,14 +110,13 @@ function get_value_timestamp(s::DataFrameDataset, date::Dates.DateTime) return s.timestamps[s_index] end -function set_value!(s::DataFrameDataset, vals, index::Int) - setindex!(s.values, vals, index, :) +function set_value!(s::InMemoryDataset, vals::DenseAxisArray{Float64, 2}, index::Int) + s.values[:, index] = vals[:, index] return end -function set_value!(s::DataFrameDataset, vals::DataFrames.DataFrame, index::Int) - @assert_op size(vals)[1] == 1 - set_value!(s, vals[1, :], index) +function set_value!(s::InMemoryDataset, vals::DenseAxisArray{Float64, 1}, index::Int) + s.values[:, index] = vals return end @@ -129,14 +129,35 @@ mutable struct HDF5Dataset <: AbstractDataset resolution::Dates.Millisecond initial_timestamp::Dates.DateTime update_timestamp::Dates.DateTime + column_names::Vector{String} + + function HDF5Dataset(values, column_dataset, write_index, last_recorded_row, resolution, + initial_timestamp, + update_timestamp, column_names, + ) + new(values, column_dataset, write_index, last_recorded_row, resolution, + initial_timestamp, + update_timestamp, column_names) + end end +#Base.length(s::HDF5Dataset) = size(s.values)[1] # TODO DT: what about the 3-dim case? +# Not getting called by tests +Base.length(s::HDF5Dataset) = error("die") + HDF5Dataset(values, column_dataset, resolution, initial_time) = - HDF5Dataset(values, column_dataset, 1, 0, resolution, initial_time, UNSET_INI_TIME) + HDF5Dataset( + values, + column_dataset, + 1, + 0, + resolution, + initial_time, + UNSET_INI_TIME, + column_dataset[:], + ) -function get_column_names(::OptimizationContainerKey, s::HDF5Dataset) - return s.column_dataset[:] -end +get_column_names(::OptimizationContainerKey, s::HDF5Dataset) = s.column_names """ Return the timestamp from most recent data row updated in the dataset. This value may not be the same as the result from `get_update_timestamp` @@ -150,6 +171,8 @@ function get_last_updated_timestamp(s::HDF5Dataset) end function get_value_timestamp(s::HDF5Dataset, date::Dates.DateTime) + # TODO: This code is broken because timestamps is not a field. + # The function is called for InMemoryDataset but not HDF5Dataset. s_index = find_timestamp_index(s.timestamps, date) if isnothing(s_index) error("Request time stamp $date not in the state") diff --git a/src/core/dataset_container.jl b/src/core/dataset_container.jl index 58c2f54818..35f1c15a7b 100644 --- a/src/core/dataset_container.jl +++ b/src/core/dataset_container.jl @@ -27,23 +27,23 @@ function Base.empty!(container::DatasetContainer) return end -function get_duals_values(container::DatasetContainer{DataFrameDataset}) +function get_duals_values(container::DatasetContainer{InMemoryDataset}) return container.duals end -function get_aux_variables_values(container::DatasetContainer{DataFrameDataset}) +function get_aux_variables_values(container::DatasetContainer{InMemoryDataset}) return container.aux_variables end -function get_variables_values(container::DatasetContainer{DataFrameDataset}) +function get_variables_values(container::DatasetContainer{InMemoryDataset}) return container.variables end -function get_parameters_values(container::DatasetContainer{DataFrameDataset}) +function get_parameters_values(container::DatasetContainer{InMemoryDataset}) return container.parameters end -function get_expression_values(container::DatasetContainer{DataFrameDataset}) +function get_expression_values(container::DatasetContainer{InMemoryDataset}) return container.expressions end @@ -133,7 +133,6 @@ function get_dataset( return get_dataset(container, ExpressionKey(T, U)) end -# Get dataset values is currently type unstable since the values field could be a DF function get_dataset_values(container::DatasetContainer, key::OptimizationContainerKey) return get_dataset(container, key).values end diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index dd58ca8ccb..0e03fc33fa 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -939,7 +939,7 @@ function get_constraint( end function read_duals(container::OptimizationContainer) - return Dict(k => axis_array_to_dataframe(v, k) for (k, v) in get_duals(container)) + return Dict(k => to_dataframe(jump_value.(v), k) for (k, v) in get_duals(container)) end ##################################### Parameter Container ################################## @@ -1203,9 +1203,9 @@ function read_parameters(container::OptimizationContainer) for (k, v) in parameters # TODO: all functions similar to calculate_parameter_values should be in one # place and be consistent in behavior. - #params_dict[k] = axis_array_to_dataframe(calculate_parameter_values(v)) - param_array = axis_array_to_dataframe(get_parameter_values(v), k) - multiplier_array = axis_array_to_dataframe(get_multiplier_array(v), k) + #params_dict[k] = to_dataframe(calculate_parameter_values(v)) + param_array = to_dataframe(get_parameter_values(v), k) + multiplier_array = to_dataframe(get_multiplier_array(v), k) params_dict[k] = _calculate_parameter_values(k, param_array, multiplier_array) end return params_dict @@ -1322,7 +1322,7 @@ end function read_expressions(container::OptimizationContainer) return Dict( - k => axis_array_to_dataframe(v, k) for (k, v) in get_expressions(container) if + k => to_dataframe(jump_value.(v), k) for (k, v) in get_expressions(container) if !(get_entry_type(k) <: SystemBalanceExpressions) ) end @@ -1395,7 +1395,7 @@ function write_initial_conditions_data!( if field == STORE_CONTAINER_PARAMETERS ic_data_dict[key] = ic_container_dict[key] else - ic_data_dict[key] = axis_array_to_dataframe(field_container, key) + ic_data_dict[key] = to_dataframe(jump_value.(field_container), key) end end end diff --git a/src/core/results_by_time.jl b/src/core/results_by_time.jl new file mode 100644 index 0000000000..70b99a5e01 --- /dev/null +++ b/src/core/results_by_time.jl @@ -0,0 +1,84 @@ +struct ResultsByTime{T} + key::OptimizationContainerKey + data::SortedDict{Dates.DateTime, T} + resolution::Dates.Period + column_names::Vector{String} +end + +function ResultsByTime(key, data, resolution, column_names) + _check_column_consistency(data, column_names) + ResultsByTime(key, data, resolution, column_names) +end + +function _check_column_consistency( + data::SortedDict{Dates.DateTime, DenseAxisArray{Float64, 2}}, + cols, +) + for val in values(data) + if axes(val)[1] != cols + error("Mismatch in DenseAxisArray column names: $(axes(val)[1]) $cols") + end + end +end + +function _check_column_consistency(data::SortedDict{Dates.DateTime, Matrix{Float64}}, cols) + for val in values(data) + if size(val)[2] != length(cols) + error("Mismatch in length of Matrix columns: $(size(val)[2]) $(length(cols))") + end + end +end + +# This struct behaves like a dict, delegating to its 'data' field. +Base.length(res::ResultsByTime) = length(res.data) +Base.iterate(res::ResultsByTime) = iterate(res.data) +Base.iterate(res::ResultsByTime, state) = iterate(res.data, state) +Base.getindex(res::ResultsByTime, i) = getindex(res.data, i) +Base.setindex!(res::ResultsByTime, v, i) = setindex!(res.data, v, i) +Base.firstindex(res::ResultsByTime) = firstindex(res.data) +Base.lastindex(res::ResultsByTime) = lastindex(res.data) + +get_column_names(x::ResultsByTime) = x.column_names +get_num_rows(::ResultsByTime{DenseAxisArray{Float64, 2}}, data) = length(axes(data)[2]) +get_num_rows(::ResultsByTime{Matrix{Float64}}, data) = size(data)[1] + +function _add_timestamps!(df::DataFrames.DataFrame, results::ResultsByTime, timestamp, data) + time_col = + range(timestamp; length = get_num_rows(results, data), step = results.resolution) + DataFrames.insertcols!(df, 1, :DateTime => time_col) +end + +function make_dataframe( + results::ResultsByTime{DenseAxisArray{Float64, 2}}, + timestamp::Dates.DateTime, +) + array = results.data[timestamp] + df = DataFrames.DataFrame(permutedims(array.data), axes(array)[1]) + _add_timestamps!(df, results, timestamp, array) + return df +end + +function make_dataframe(results::ResultsByTime{Matrix{Float64}}, timestamp::Dates.DateTime) + array = results.data[timestamp] + df = DataFrames.DataFrame(array, results.column_names) + _add_timestamps!(df, results, timestamp, array) + return df +end + +function make_dataframes(results::ResultsByTime) + return SortedDict(k => make_dataframe(results, k) for k in keys(results.data)) +end + +struct ResultsByKeyAndTime + "Contains all keys stored in the model." + result_keys::Vector{OptimizationContainerKey} + "Contains the results that have been read from the store and cached." + cached_results::Dict{OptimizationContainerKey, ResultsByTime} +end + +ResultsByKeyAndTime(result_keys) = ResultsByKeyAndTime( + collect(result_keys), + Dict{OptimizationContainerKey, ResultsByTime}(), +) + +Base.empty!(res::ResultsByKeyAndTime) = empty!(res.cached_results) diff --git a/src/core/store_common.jl b/src/core/store_common.jl index 00996f65fd..9f29279d7c 100644 --- a/src/core/store_common.jl +++ b/src/core/store_common.jl @@ -53,14 +53,15 @@ function write_model_dual_results!( for (key, constraint) in get_duals(container) !should_write_resulting_value(key) && continue - write_result!(store, model_name, key, index, update_timestamp, constraint) + data = jump_value.(constraint) + write_result!(store, model_name, key, index, update_timestamp, data) if export_params !== nothing && should_export_dual(export_params[:exports], index, model_name, key) horizon = export_params[:horizon] resolution = export_params[:resolution] file_type = export_params[:file_type] - df = axis_array_to_dataframe(constraint, key) + df = to_dataframe(jump_value.(constraint), key) time_col = range(index; length = horizon, step = resolution) DataFrames.insertcols!(df, 1, :DateTime => time_col) export_result(file_type, exports_path, key, index, df) @@ -95,7 +96,11 @@ function write_model_parameter_results!( should_export_parameter(export_params[:exports], index, model_name, key) resolution = export_params[:resolution] file_type = export_params[:file_type] - df = axis_array_to_dataframe(data, key) + # TODO DT: why was jump_value being called again? + # (first time was in calculate_parameter_values) + # Was it always a noop? + df = to_dataframe(data, key) + #df = to_dataframe(jump_value.(data), key) time_col = range(index; length = horizon, step = resolution) DataFrames.insertcols!(df, 1, :DateTime => time_col) export_result(file_type, exports_path, key, index, df) @@ -126,14 +131,15 @@ function write_model_variable_results!( for (key, variable) in variables !should_write_resulting_value(key) && continue - write_result!(store, model_name, key, index, update_timestamp, variable) + data = jump_value.(variable) + write_result!(store, model_name, key, index, update_timestamp, data) if export_params !== nothing && should_export_variable(export_params[:exports], index, model_name, key) horizon = export_params[:horizon] resolution = export_params[:resolution] file_type = export_params[:file_type] - df = axis_array_to_dataframe(variable, key) + df = to_dataframe(data, key) time_col = range(index; length = horizon, step = resolution) DataFrames.insertcols!(df, 1, :DateTime => time_col) export_result(file_type, exports_path, key, index, df) @@ -158,14 +164,15 @@ function write_model_aux_variable_results!( for (key, variable) in get_aux_variables(container) !should_write_resulting_value(key) && continue - write_result!(store, model_name, key, index, update_timestamp, variable) + data = jump_value.(variable) + write_result!(store, model_name, key, index, update_timestamp, data) if export_params !== nothing && should_export_aux_variable(export_params[:exports], index, model_name, key) horizon = export_params[:horizon] resolution = export_params[:resolution] file_type = export_params[:file_type] - df = axis_array_to_dataframe(variable, key) + df = to_dataframe(data, key) time_col = range(index; length = horizon, step = resolution) DataFrames.insertcols!(df, 1, :DateTime => time_col) export_result(file_type, exports_path, key, index, df) @@ -196,14 +203,15 @@ function write_model_expression_results!( for (key, expression) in expressions !should_write_resulting_value(key) && continue - write_result!(store, model_name, key, index, update_timestamp, expression) + data = jump_value.(expression) + write_result!(store, model_name, key, index, update_timestamp, data) if export_params !== nothing && should_export_expression(export_params[:exports], index, model_name, key) horizon = export_params[:horizon] resolution = export_params[:resolution] file_type = export_params[:file_type] - df = axis_array_to_dataframe(expression, key) + df = to_dataframe(data, key) time_col = range(index; length = horizon, step = resolution) DataFrames.insertcols!(df, 1, :DateTime => time_col) export_result(file_type, exports_path, key, index, df) diff --git a/src/operation/abstract_model_store.jl b/src/operation/abstract_model_store.jl index 767d22ed77..ff7c57f684 100644 --- a/src/operation/abstract_model_store.jl +++ b/src/operation/abstract_model_store.jl @@ -53,15 +53,6 @@ function read_results(store::AbstractModelStore, key; index = nothing) return read_results(store, field, key; index = index) end -function read_results( - ::Type{DataFrames.DataFrame}, - store::AbstractModelStore, - key; - index = nothing, -) - return read_results(store, key; index = index) -end - function list_keys(store::AbstractModelStore, container_type) container = get_data_field(store, container_type) return collect(keys(container)) diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index 8427b0fa7d..623aab96db 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -463,7 +463,7 @@ end function update_parameters!( model::DecisionModel, - decision_states::DatasetContainer{DataFrameDataset}, + decision_states::DatasetContainer{InMemoryDataset}, ) cost_function_unsynch(get_optimization_container(model)) for key in keys(get_parameters(model)) diff --git a/src/operation/decision_model_store.jl b/src/operation/decision_model_store.jl index 30efdf3c84..a6323dfd2d 100644 --- a/src/operation/decision_model_store.jl +++ b/src/operation/decision_model_store.jl @@ -2,36 +2,25 @@ Stores results data for one DecisionModel """ mutable struct DecisionModelStore <: AbstractModelStore - duals::Dict{ConstraintKey, OrderedDict{Dates.DateTime, DataFrames.DataFrame}} - parameters::Dict{ParameterKey, OrderedDict{Dates.DateTime, DataFrames.DataFrame}} - variables::Dict{VariableKey, OrderedDict{Dates.DateTime, DataFrames.DataFrame}} - aux_variables::Dict{AuxVarKey, OrderedDict{Dates.DateTime, DataFrames.DataFrame}} - expressions::Dict{ExpressionKey, OrderedDict{Dates.DateTime, DataFrames.DataFrame}} + # All DenseAxisArrays have axes (column names, row indexes) + duals::Dict{ConstraintKey, OrderedDict{Dates.DateTime, DenseAxisArray{Float64, 2}}} + parameters::Dict{ParameterKey, OrderedDict{Dates.DateTime, DenseAxisArray{Float64, 2}}} + variables::Dict{VariableKey, OrderedDict{Dates.DateTime, DenseAxisArray{Float64, 2}}} + aux_variables::Dict{AuxVarKey, OrderedDict{Dates.DateTime, DenseAxisArray{Float64, 2}}} + expressions::Dict{ + ExpressionKey, + OrderedDict{Dates.DateTime, DenseAxisArray{Float64, 2}}, + } optimizer_stats::OrderedDict{Dates.DateTime, OptimizerStats} end function DecisionModelStore() return DecisionModelStore( - Dict{ - ConstraintKey, - Dict{ConstraintKey, OrderedDict{Dates.DateTime, DataFrames.DataFrame}}, - }(), - Dict{ - ParameterKey, - Dict{ParameterKey, OrderedDict{Dates.DateTime, DataFrames.DataFrame}}, - }(), - Dict{ - VariableKey, - Dict{VariableKey, OrderedDict{Dates.DateTime, DataFrames.DataFrame}}, - }(), - Dict{ - AuxVarKey, - Dict{ConstraintKey, OrderedDict{Dates.DateTime, DataFrames.DataFrame}}, - }(), - Dict{ - AuxVarKey, - Dict{ExpressionKey, OrderedDict{Dates.DateTime, DataFrames.DataFrame}}, - }(), + Dict{ConstraintKey, OrderedDict{Dates.DateTime, DenseAxisArray{Float64, 2}}}(), + Dict{ParameterKey, OrderedDict{Dates.DateTime, DenseAxisArray{Float64, 2}}}(), + Dict{VariableKey, OrderedDict{Dates.DateTime, DenseAxisArray{Float64, 2}}}(), + Dict{AuxVarKey, OrderedDict{Dates.DateTime, DenseAxisArray{Float64, 2}}}(), + Dict{ExpressionKey, OrderedDict{Dates.DateTime, DenseAxisArray{Float64, 2}}}(), OrderedDict{Dates.DateTime, OptimizerStats}(), ) end @@ -52,14 +41,16 @@ function initialize_storage!( !should_write_resulting_value(key) && continue @debug "Adding $(encode_key_as_string(key)) to DecisionModelStore" _group = LOG_GROUP_MODEL_STORE - results_container[key] = OrderedDict{Dates.DateTime, DataFrames.DataFrame}() column_names = get_column_names(key, field_container) + data = OrderedDict{Dates.DateTime, DenseAxisArray{Float64, 2}}() for timestamp in range(initial_time; step = model_interval, length = num_of_executions) - results_container[key][timestamp] = DataFrames.DataFrame( - OrderedDict(c => fill(NaN, time_steps_count) for c in column_names), + data[timestamp] = fill!( + DenseAxisArray{Float64}(undef, column_names, 1:time_steps_count), + NaN, ) end + results_container[key] = data end end end @@ -70,23 +61,15 @@ function write_result!( key::OptimizationContainerKey, index::DecisionModelIndexType, update_timestamp::Dates.DateTime, - array::AbstractArray, -) - df = axis_array_to_dataframe(array, key) - write_result!(store, name, key, index, update_timestamp, df) - return -end - -function write_result!( - store::DecisionModelStore, - ::Symbol, - key::OptimizationContainerKey, - index::DecisionModelIndexType, - update_timestamp::Dates.DateTime, - df::Union{DataFrames.DataFrame, DataFrames.DataFrameRow}, + array::DenseAxisArray{<:Any, 2}, ) + columns = axes(array)[1] + if eltype(columns) !== String + # TODO: This happens because buses are stored by indexes instead of name. + columns = string.(columns) + end container = getfield(store, get_store_container_type(key)) - container[key][index] = df + container[key][index] = DenseAxisArray(array.data, columns, 1:size(array)[2]) return end @@ -103,7 +86,7 @@ function read_results( end # Return a copy because callers may mutate it. - return copy(data[index]; copycols = true) + return deepcopy(data[index]) end function write_optimizer_stats!( @@ -124,3 +107,8 @@ function read_optimizer_stats(store::DecisionModelStore) DataFrames.insertcols!(df, 1, :DateTime => keys(store.optimizer_stats)) return df end + +function get_column_names(store::DecisionModelStore, key::OptimizationContainerKey) + container = getfield(store, get_store_container_type(key)) + return axes(first(values(container[key])))[1] +end diff --git a/src/operation/emulation_model.jl b/src/operation/emulation_model.jl index 0a18b644d1..724134c344 100644 --- a/src/operation/emulation_model.jl +++ b/src/operation/emulation_model.jl @@ -319,7 +319,7 @@ function update_parameters!(model::EmulationModel, store::EmulationModelStore) return end -function update_parameters!(model::EmulationModel, data::DatasetContainer{DataFrameDataset}) +function update_parameters!(model::EmulationModel, data::DatasetContainer{InMemoryDataset}) cost_function_unsynch(get_optimization_container(model)) for key in keys(get_parameters(model)) update_parameter_values!(model, key, data) diff --git a/src/operation/emulation_model_store.jl b/src/operation/emulation_model_store.jl index 9f6af99da0..fe468b6483 100644 --- a/src/operation/emulation_model_store.jl +++ b/src/operation/emulation_model_store.jl @@ -2,7 +2,7 @@ Stores results data for one EmulationModel """ mutable struct EmulationModelStore <: AbstractModelStore - data_container::DatasetContainer{DataFrameDataset} + data_container::DatasetContainer{InMemoryDataset} optimizer_stats::OrderedDict{Int, OptimizerStats} end @@ -11,7 +11,7 @@ get_data_field(store::EmulationModelStore, type::Symbol) = function EmulationModelStore() return EmulationModelStore( - DatasetContainer{DataFrameDataset}(), + DatasetContainer{InMemoryDataset}(), OrderedDict{Int, OptimizerStats}(), ) end @@ -55,7 +55,7 @@ function Base.isempty(store::EmulationModelStore) elseif name == :update_timestamp store.update_timestamp != UNSET_INI_TIME && return false else - val = get_data_fieldd(store, name) + val = get_data_field(store, name) iszero(val) && return false end end @@ -75,9 +75,10 @@ function initialize_storage!( @debug "Adding $(encode_key_as_string(key)) to EmulationModelStore" _group = LOG_GROUP_MODEL_STORE column_names = get_column_names(key, field_container) - results_container[key] = DataFrameDataset( - DataFrames.DataFrame( - OrderedDict(c => fill(NaN, num_of_executions) for c in column_names), + results_container[key] = InMemoryDataset( + fill!( + DenseAxisArray{Float64}(undef, column_names, 1:num_of_executions), + NaN, ), ) end @@ -91,23 +92,10 @@ function write_result!( key::OptimizationContainerKey, index::EmulationModelIndexType, update_timestamp::Dates.DateTime, - array::AbstractArray, + array::DenseAxisArray{<:Any, 2}, ) - df = axis_array_to_dataframe(array, key) - write_result!(store, name, key, index, update_timestamp, df) - return -end - -function write_result!( - store::EmulationModelStore, - name::Symbol, - key::OptimizationContainerKey, - index::EmulationModelIndexType, - update_timestamp::Dates.DateTime, - df::DataFrames.DataFrame, -) - @assert_op size(df)[1] == 1 - write_result!(store, name, key, index, update_timestamp, df[1, :]) + @assert_op size(array)[2] == 1 + write_result!(store, name, key, index, update_timestamp, array[:, 1]) return end @@ -117,10 +105,14 @@ function write_result!( key::OptimizationContainerKey, index::EmulationModelIndexType, update_timestamp::Dates.DateTime, - df_row::DataFrames.DataFrameRow, + array::DenseAxisArray{<:Any, 1}, ) container = get_data_field(store, get_store_container_type(key)) - set_value!(container[key], df_row, index) + set_value!( + container[key], + array, + index, + ) set_last_recorded_row!(container[key], index) set_update_timestamp!(container[key], update_timestamp) return @@ -133,18 +125,23 @@ function read_results( len::Union{Int, Nothing} = nothing, ) container = get_data_field(store, get_store_container_type(key)) - df = container[key].values + data = container[key].values # Return a copy because callers may mutate it. if isnothing(index) @assert_op len === nothing - return copy(df; copycols = true) + return data[:, :] elseif isnothing(len) - return copy(df; copycols = true)[index:end, :] + return data[:, index:end] else - return copy(df; copycols = true)[index:(index + len - 1), :] + return data[:, index:(index + len - 1)] end end +function get_column_names(store::EmulationModelStore, key::OptimizationContainerKey) + container = get_data_field(store, get_store_container_type(key)) + return axes(container[key].values)[1] +end + function get_dataset_size(store::EmulationModelStore, key::OptimizationContainerKey) container = get_data_field(store, get_store_container_type(key)) return size(container[key].values) diff --git a/src/operation/operation_model_interface.jl b/src/operation/operation_model_interface.jl index ecd0b99d7a..fb2b302e5b 100644 --- a/src/operation/operation_model_interface.jl +++ b/src/operation/operation_model_interface.jl @@ -315,24 +315,15 @@ function _list_names(model::OperationModel, container_type) return encode_keys_as_strings(list_keys(get_store(model), container_type)) end -function read_dual(model::OperationModel, key::ConstraintKey) - return read_results(get_store(model), key) -end - -function read_parameter(model::OperationModel, key::ParameterKey) - return read_results(get_store(model), key) -end - -function read_aux_variable(model::OperationModel, key::AuxVarKey) - return read_results(get_store(model), key) -end - -function read_variable(model::OperationModel, key::VariableKey) - return read_results(get_store(model), key) -end - -function read_expression(model::OperationModel, key::ExpressionKey) - return read_results(get_store(model), key) +read_dual(model::OperationModel, key::ConstraintKey) = _read_results(model, key) +read_parameter(model::OperationModel, key::ParameterKey) = _read_results(model, key) +read_aux_variable(model::OperationModel, key::AuxVarKey) = _read_results(model, key) +read_variable(model::OperationModel, key::VariableKey) = _read_results(model, key) +read_expression(model::OperationModel, key::ExpressionKey) = _read_results(model, key) + +function _read_results(model::OperationModel, key::OptimizationContainerKey) + res = read_results(get_store(model), key) + return DataFrames.DataFrame(permutedims(res.data), axes(res)[1]) end read_optimizer_stats(model::OperationModel) = read_optimizer_stats(get_store(model)) diff --git a/src/operation/problem_results.jl b/src/operation/problem_results.jl index 4f76a4677d..44e07336d1 100644 --- a/src/operation/problem_results.jl +++ b/src/operation/problem_results.jl @@ -41,6 +41,12 @@ get_resolution(res::ProblemResults) = res.timestamps.step get_system(res::ProblemResults) = res.system get_forecast_horizon(res::ProblemResults) = length(get_timestamps(res)) +get_result_values(x::ProblemResults, ::AuxVarKey) = x.aux_variable_values +get_result_values(x::ProblemResults, ::ConstraintKey) = x.dual_values +get_result_values(x::ProblemResults, ::ExpressionKey) = x.expression_values +get_result_values(x::ProblemResults, ::ParameterKey) = x.parameter_values +get_result_values(x::ProblemResults, ::VariableKey) = x.variable_values + function get_objective_value(res::ProblemResults, execution = 1) return res.optimizer_stats[execution, :objective_value] end @@ -297,7 +303,7 @@ function _read_results( container_keys, timestamps, time_ids, - base_power, + base_power::Number, ) existing_keys = keys(result_values) container_keys = container_keys === nothing ? existing_keys : container_keys @@ -372,7 +378,7 @@ function read_variable( start_time::Union{Nothing, Dates.DateTime} = nothing, len::Union{Int, Nothing} = nothing, ) - return read_variables_with_keys(res, [key]; start_time = start_time, len = len)[key] + return read_results_with_keys(res, [key]; start_time = start_time, len = len)[key] end """ @@ -405,7 +411,7 @@ function read_variables( len::Union{Int, Nothing} = nothing, ) result_values = - read_variables_with_keys(res, variables; start_time = start_time, len = len) + read_results_with_keys(res, variables; start_time = start_time, len = len) return Dict(encode_key_as_string(k) => v for (k, v) in result_values) end @@ -413,23 +419,7 @@ end Return the values for all variables. """ function read_variables(res::IS.Results) - variables = Dict(x => read_variable(res, x) for x in list_variable_names(res)) -end - -function read_variables_with_keys( - res::ProblemResults, - variables::Vector{<:OptimizationContainerKey}; - start_time::Union{Nothing, Dates.DateTime} = nothing, - len::Union{Int, Nothing} = nothing, -) - (timestamp_ids, timestamps) = _process_timestamps(res, start_time, len) - return _read_results( - res.variable_values, - variables, - timestamps, - timestamp_ids, - get_model_base_power(res), - ) + return Dict(x => read_variable(res, x) for x in list_variable_names(res)) end """ @@ -458,7 +448,7 @@ function read_dual( start_time::Union{Nothing, Dates.DateTime} = nothing, len::Union{Int, Nothing} = nothing, ) - return read_duals_with_keys(res, [key]; start_time = start_time, len = len)[key] + return read_results_with_keys(res, [key]; start_time = start_time, len = len)[key] end """ @@ -490,7 +480,7 @@ function read_duals( start_time::Union{Nothing, Dates.DateTime} = nothing, len::Union{Int, Nothing} = nothing, ) - result_values = read_duals_with_keys(res, duals; start_time = start_time, len = len) + result_values = read_results_with_keys(res, duals; start_time = start_time, len = len) return Dict(encode_key_as_string(k) => v for (k, v) in result_values) end @@ -501,22 +491,6 @@ function read_duals(res::IS.Results) duals = Dict(x => read_dual(res, x) for x in list_dual_names(res)) end -function read_duals_with_keys( - res::ProblemResults, - duals::Vector{<:OptimizationContainerKey}; - start_time::Union{Nothing, Dates.DateTime} = nothing, - len::Union{Int, Nothing} = nothing, -) - (timestamp_ids, timestamps) = _process_timestamps(res, start_time, len) - return _read_results( - res.dual_values, - duals, - timestamps, - timestamp_ids, - get_model_base_power(res), - ) -end - """ Return the values for the requested parameter key for a problem. Accepts a vector of keys for the return of the values. If the time stamps and keys are @@ -543,7 +517,7 @@ function read_parameter( start_time::Union{Nothing, Dates.DateTime} = nothing, len::Union{Int, Nothing} = nothing, ) - return read_parameters_with_keys(res, [key]; start_time = start_time, len = len)[key] + return read_results_with_keys(res, [key]; start_time = start_time, len = len)[key] end """ @@ -580,7 +554,7 @@ function read_parameters( len::Union{Int, Nothing} = nothing, ) result_values = - read_parameters_with_keys(res, parameters; start_time = start_time, len = len) + read_results_with_keys(res, parameters; start_time = start_time, len = len) return Dict(encode_key_as_string(k) => v for (k, v) in result_values) end @@ -591,22 +565,6 @@ function read_parameters(res::IS.Results) parameters = Dict(x => read_parameter(res, x) for x in list_parameter_names(res)) end -function read_parameters_with_keys( - res::ProblemResults, - parameters::Vector{<:OptimizationContainerKey}; - start_time::Union{Nothing, Dates.DateTime} = nothing, - len::Union{Int, Nothing} = nothing, -) - (timestamp_ids, timestamps) = _process_timestamps(res, start_time, len) - return _read_results( - res.parameter_values, - parameters, - timestamps, - timestamp_ids, - get_model_base_power(res), - ) -end - """ Return the values for the requested aux_variable key for a problem. Accepts a vector of keys for the return of the values. If the time stamps and keys are @@ -633,7 +591,7 @@ function read_aux_variable( start_time::Union{Nothing, Dates.DateTime} = nothing, len::Union{Int, Nothing} = nothing, ) - return read_aux_variables_with_keys(res, [key]; start_time = start_time, len = len)[key] + return read_results_with_keys(res, [key]; start_time = start_time, len = len)[key] end """ @@ -670,7 +628,7 @@ function read_aux_variables( len::Union{Int, Nothing} = nothing, ) result_values = - read_aux_variables_with_keys(res, aux_variables; start_time = start_time, len = len) + read_results_with_keys(res, aux_variables; start_time = start_time, len = len) return Dict(encode_key_as_string(k) => v for (k, v) in result_values) end @@ -678,23 +636,7 @@ end Return the values for all auxiliary variables. """ function read_aux_variables(res::IS.Results) - variables = Dict(x => read_aux_variable(res, x) for x in list_aux_variable_names(res)) -end - -function read_aux_variables_with_keys( - res::ProblemResults, - aux_variables::Vector{<:OptimizationContainerKey}; - start_time::Union{Nothing, Dates.DateTime} = nothing, - len::Union{Int, Nothing} = nothing, -) - (timestamp_ids, timestamps) = _process_timestamps(res, start_time, len) - return _read_results( - res.aux_variable_values, - aux_variables, - timestamps, - timestamp_ids, - get_model_base_power(res), - ) + return Dict(x => read_aux_variable(res, x) for x in list_aux_variable_names(res)) end """ @@ -723,7 +665,7 @@ function read_expression( start_time::Union{Nothing, Dates.DateTime} = nothing, len::Union{Int, Nothing} = nothing, ) - return read_expressions_with_keys(res, [key]; start_time = start_time, len = len)[key] + return read_results_with_keys(res, [key]; start_time = start_time, len = len)[key] end """ @@ -764,7 +706,7 @@ function read_expressions( len::Union{Int, Nothing} = nothing, ) result_values = - read_expressions_with_keys(res, expressions; start_time = start_time, len = len) + read_results_with_keys(res, expressions; start_time = start_time, len = len) return Dict(encode_key_as_string(k) => v for (k, v) in result_values) end @@ -772,19 +714,20 @@ end Return the values for all expressions. """ function read_expressions(res::IS.Results) - expressions = Dict(x => read_expression(res, x) for x in list_expression_names(res)) + return Dict(x => read_expression(res, x) for x in list_expression_names(res)) end -function read_expressions_with_keys( +function read_results_with_keys( res::ProblemResults, - expressions::Vector{<:OptimizationContainerKey}; + result_keys::Vector{<:OptimizationContainerKey}; start_time::Union{Nothing, Dates.DateTime} = nothing, len::Union{Int, Nothing} = nothing, ) + isempty(result_keys) && return Dict{OptimizationContainerKey, DataFrames.DataFrame}() (timestamp_ids, timestamps) = _process_timestamps(res, start_time, len) return _read_results( - res.expression_values, - expressions, + get_result_values(res, first(result_keys)), + result_keys, timestamps, timestamp_ids, get_model_base_power(res), diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index 6a01c8b4e7..ef942d3ee4 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -52,7 +52,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, ::Type{V}, model::DecisionModel, - ::DatasetContainer{DataFrameDataset}, + ::DatasetContainer{InMemoryDataset}, ) where { T <: Union{JuMP.VariableRef, Float64}, U <: PSY.AbstractDeterministic, @@ -96,7 +96,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, service::V, model::DecisionModel, - ::DatasetContainer{DataFrameDataset}, + ::DatasetContainer{InMemoryDataset}, ) where { T <: Union{JuMP.VariableRef, Float64}, U <: PSY.AbstractDeterministic, @@ -129,7 +129,7 @@ function _update_parameter_values!( attributes::TimeSeriesAttributes{U}, ::Type{V}, model::EmulationModel, - ::DatasetContainer{DataFrameDataset}, + ::DatasetContainer{InMemoryDataset}, ) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.SingleTimeSeries, V <: PSY.Device} initial_forecast_time = get_current_time(model) template = get_template(model) @@ -166,7 +166,7 @@ function _update_parameter_values!( attributes::VariableValueAttributes, ::Type{<:PSY.Component}, model::DecisionModel, - state::DatasetContainer{DataFrameDataset}, + state::DatasetContainer{InMemoryDataset}, ) where {T <: Union{JuMP.VariableRef, Float64}} current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) @@ -187,7 +187,7 @@ function _update_parameter_values!( end for name in component_names # Pass indices in this way since JuMP DenseAxisArray don't support view() - state_value = state_values[state_data_index, name] + state_value = state_values[name, state_data_index] if !isfinite(state_value) error( "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))) is not a finite value $(state_value) \ @@ -206,7 +206,7 @@ function _update_parameter_values!( attributes::VariableValueAttributes{VariableKey{OnVariable, U}}, ::Type{U}, model::DecisionModel, - state::DatasetContainer{DataFrameDataset}, + state::DatasetContainer{InMemoryDataset}, ) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.Component} current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) @@ -228,7 +228,7 @@ function _update_parameter_values!( end for name in component_names # Pass indices in this way since JuMP DenseAxisArray don't support view() - value = round(state_values[state_data_index, name]) + value = round(state_values[name, state_data_index]) @assert 0.0 <= value <= 1.0 if !isfinite(value) error( @@ -248,7 +248,7 @@ function _update_parameter_values!( attributes::VariableValueAttributes, ::Type{<:PSY.Component}, model::EmulationModel, - state::DatasetContainer{DataFrameDataset}, + state::DatasetContainer{InMemoryDataset}, ) where {T <: Union{JuMP.VariableRef, Float64}} current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) @@ -258,7 +258,7 @@ function _update_parameter_values!( state_data_index = find_timestamp_index(state_timestamps, current_time) for name in component_names # Pass indices in this way since JuMP DenseAxisArray don't support view() - _set_param_value!(parameter_array, state_values[state_data_index, name], name, 1) + _set_param_value!(parameter_array, state_values[name, state_data_index], name, 1) end return end @@ -268,7 +268,7 @@ function _update_parameter_values!( attributes::VariableValueAttributes{VariableKey{OnVariable, U}}, ::Type{<:PSY.Component}, model::EmulationModel, - state::DatasetContainer{DataFrameDataset}, + state::DatasetContainer{InMemoryDataset}, ) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.Component} current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) @@ -278,7 +278,7 @@ function _update_parameter_values!( state_data_index = find_timestamp_index(state_timestamps, current_time) for name in component_names # Pass indices in this way since JuMP DenseAxisArray don't support view() - value = round(state_values[state_data_index, name]) + value = round(state_values[name, state_data_index]) @assert 0.0 <= value <= 1.0 if !isfinite(value) error( @@ -309,7 +309,7 @@ Update parameter function an OperationModel function update_parameter_values!( model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{DataFrameDataset}, + input::DatasetContainer{InMemoryDataset}, ) where {T <: ParameterType, U <: PSY.Component} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin @@ -333,7 +333,7 @@ end function update_parameter_values!( model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{DataFrameDataset}, + input::DatasetContainer{InMemoryDataset}, ) where {T <: ObjectiveFunctionParameter, U <: PSY.Component} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin @@ -366,7 +366,7 @@ end function update_parameter_values!( model::OperationModel, key::ParameterKey{FixValueParameter, T}, - input::DatasetContainer{DataFrameDataset}, + input::DatasetContainer{InMemoryDataset}, ) where {T <: PSY.Component} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin @@ -391,7 +391,7 @@ end function update_parameter_values!( model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{DataFrameDataset}, + input::DatasetContainer{InMemoryDataset}, ) where {T <: EnergyLimitParameter, U <: PSY.Generator} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin @@ -429,7 +429,7 @@ function update_parameter_values!( # that are equal to the length of the interval i.e. the time periods that dont overlap between each solves. if execution_count == 0 || t > time[end] - interval_time_steps # Pass indices in this way since JuMP DenseAxisArray don't support view() - state_value = state_values[state_data_index, name] + state_value = state_values[name, state_data_index] if !isfinite(state_value) error( "The value for the system state used in $(encode_key_as_string(key)) is not a finite value $(state_value) \ @@ -442,7 +442,7 @@ function update_parameter_values!( # Currently the update method relies on using older parameter values of the EnergyLimitParameter # to update the parameter for overlapping periods between solves i.e. we ingoring the parameter values # in the model interval time periods. - state_value = state_values[state_data_index, name] + state_value = state_values[name, state_data_index] if !isfinite(state_value) error( "The value for the system state used in $(encode_key_as_string(key)) is not a finite value $(state_value) \ @@ -476,7 +476,7 @@ Update parameter function an OperationModel function update_parameter_values!( model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{DataFrameDataset}, + input::DatasetContainer{InMemoryDataset}, ) where {T <: ParameterType, U <: PSY.Service} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin @@ -502,7 +502,7 @@ end function update_parameter_values!( model::OperationModel, key::ParameterKey{T, U}, - input::DatasetContainer{DataFrameDataset}, + input::DatasetContainer{InMemoryDataset}, ) where {T <: ObjectiveFunctionParameter, U <: PSY.Service} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin @@ -544,7 +544,7 @@ end function update_parameter_values!( model::OperationModel, key::ParameterKey{FixValueParameter, T}, - input::DatasetContainer{DataFrameDataset}, + input::DatasetContainer{InMemoryDataset}, ) where {T <: PSY.Service} # Enable again for detailed debugging # TimerOutputs.@timeit RUN_SIMULATION_TIMER "$T $U Parameter Update" begin @@ -572,7 +572,7 @@ function _update_parameter_values!( attributes::CostFunctionAttributes, ::Type{V}, model::DecisionModel, - ::DatasetContainer{DataFrameDataset}, + ::DatasetContainer{InMemoryDataset}, ) where {V <: PSY.Component} initial_forecast_time = get_current_time(model) # Function not well defined for DecisionModels time_steps = get_time_steps(get_optimization_container(model)) diff --git a/src/simulation/decision_model_simulation_results.jl b/src/simulation/decision_model_simulation_results.jl index ef06defb14..0864774575 100644 --- a/src/simulation/decision_model_simulation_results.jl +++ b/src/simulation/decision_model_simulation_results.jl @@ -1,10 +1,9 @@ - struct DecisionModelSimulationResults <: OperationModelSimulationResults - variables::FieldResultsByTime - duals::FieldResultsByTime - parameters::FieldResultsByTime - aux_variables::FieldResultsByTime - expressions::FieldResultsByTime + variables::ResultsByKeyAndTime + duals::ResultsByKeyAndTime + parameters::ResultsByKeyAndTime + aux_variables::ResultsByKeyAndTime + expressions::ResultsByKeyAndTime forecast_horizon::Int container_key_lookup::Dict{String, OptimizationContainerKey} end @@ -20,12 +19,6 @@ function SimulationProblemResults( kwargs..., ) name = Symbol(model_name) - variables = list_decision_model_keys(store, name, STORE_CONTAINER_VARIABLES) - parameters = list_decision_model_keys(store, name, STORE_CONTAINER_PARAMETERS) - duals = list_decision_model_keys(store, name, STORE_CONTAINER_DUALS) - aux_variables = list_decision_model_keys(store, name, STORE_CONTAINER_AUX_VARIABLES) - expressions = list_decision_model_keys(store, name, STORE_CONTAINER_EXPRESSIONS) - return SimulationProblemResults{DecisionModelSimulationResults}( store, model_name, @@ -33,11 +26,21 @@ function SimulationProblemResults( sim_params, path, DecisionModelSimulationResults( - _fill_result_value_container(variables), - _fill_result_value_container(duals), - _fill_result_value_container(parameters), - _fill_result_value_container(aux_variables), - _fill_result_value_container(expressions), + ResultsByKeyAndTime( + list_decision_model_keys(store, name, STORE_CONTAINER_VARIABLES), + ), + ResultsByKeyAndTime( + list_decision_model_keys(store, name, STORE_CONTAINER_DUALS), + ), + ResultsByKeyAndTime( + list_decision_model_keys(store, name, STORE_CONTAINER_PARAMETERS), + ), + ResultsByKeyAndTime( + list_decision_model_keys(store, name, STORE_CONTAINER_AUX_VARIABLES), + ), + ResultsByKeyAndTime( + list_decision_model_keys(store, name, STORE_CONTAINER_EXPRESSIONS), + ), get_horizon(problem_params), container_key_lookup, ); @@ -45,71 +48,147 @@ function SimulationProblemResults( ) end +function _list_containers(res::SimulationProblemResults{DecisionModelSimulationResults}) + return (getfield(res.values, x).cached_results for x in get_container_fields(res)) +end + function Base.empty!(res::SimulationProblemResults{DecisionModelSimulationResults}) - foreach(empty!, _get_dicts(res)) + foreach(empty!, _list_containers(res)) empty!(res.results_timestamps) - return end -Base.isempty(res::SimulationProblemResults{DecisionModelSimulationResults}) = - all(isempty, _get_dicts(res)) +function Base.isempty(res::SimulationProblemResults{DecisionModelSimulationResults}) + all(isempty, _list_containers(res)) +end # This returns the number of timestamps stored in all containers. -Base.length(res::SimulationProblemResults{DecisionModelSimulationResults}) = - mapreduce(length, +, _get_dicts(res)) +function Base.length(res::SimulationProblemResults{DecisionModelSimulationResults}) + return mapreduce(length, +, (y for x in _list_containers(res) for y in values(x))) +end -_get_dicts(res::SimulationProblemResults) = - (y for x in _get_containers(res) for y in values(x)) +list_aux_variable_keys(res::SimulationProblemResults{DecisionModelSimulationResults}) = + res.values.aux_variables.result_keys[:] +list_dual_keys(res::SimulationProblemResults{DecisionModelSimulationResults}) = + res.values.duals.result_keys[:] +list_expression_keys(res::SimulationProblemResults{DecisionModelSimulationResults}) = + res.values.expressions.result_keys[:] +list_parameter_keys(res::SimulationProblemResults{DecisionModelSimulationResults}) = + res.values.parameters.result_keys[:] +list_variable_keys(res::SimulationProblemResults{DecisionModelSimulationResults}) = + res.values.variables.result_keys[:] + +get_cached_aux_variables(res::SimulationProblemResults{DecisionModelSimulationResults}) = + res.values.aux_variables.cached_results +get_cached_duals(res::SimulationProblemResults{DecisionModelSimulationResults}) = + res.values.duals.cached_results +get_cached_expressions(res::SimulationProblemResults{DecisionModelSimulationResults}) = + res.values.expressions.cached_results +get_cached_parameters(res::SimulationProblemResults{DecisionModelSimulationResults}) = + res.values.parameters.cached_results +get_cached_variables(res::SimulationProblemResults{DecisionModelSimulationResults}) = + res.values.variables.cached_results + +get_cached_results( + res::SimulationProblemResults{DecisionModelSimulationResults}, + ::AuxVarKey, +) = get_cached_aux_variables(res) +get_cached_results( + res::SimulationProblemResults{DecisionModelSimulationResults}, + ::ConstraintKey, +) = get_cached_duals(res) +get_cached_results( + res::SimulationProblemResults{DecisionModelSimulationResults}, + ::ExpressionKey, +) = get_cached_expressions(res) +get_cached_results( + res::SimulationProblemResults{DecisionModelSimulationResults}, + ::ParameterKey, +) = get_cached_parameters(res) +get_cached_results( + res::SimulationProblemResults{DecisionModelSimulationResults}, + ::VariableKey, +) = get_cached_variables(res) function get_forecast_horizon(res::SimulationProblemResults{DecisionModelSimulationResults}) return res.values.forecast_horizon end function _get_store_value( + ::Type{T}, res::SimulationProblemResults{DecisionModelSimulationResults}, container_keys::Vector{<:OptimizationContainerKey}, timestamps, ::Nothing, -) +) where {T <: Union{Matrix{Float64}, DenseAxisArray{Float64, 2}}} simulation_store_path = joinpath(get_execution_path(res), "data_store") return open_store(HdfSimulationStore, simulation_store_path, "r") do store - _get_store_value(res, container_keys, timestamps, store) + _get_store_value(T, res, container_keys, timestamps, store) end end function _get_store_value( - res::SimulationProblemResults{DecisionModelSimulationResults}, + ::Type{DenseAxisArray{Float64, 2}}, + sim_results::SimulationProblemResults{DecisionModelSimulationResults}, container_keys::Vector{<:OptimizationContainerKey}, timestamps, store::SimulationStore, ) - base_power = get_model_base_power(res) - results = - Dict{OptimizationContainerKey, SortedDict{Dates.DateTime, DataFrames.DataFrame}}() - model_name = Symbol(get_model_name(res)) - resolution = get_resolution(res) - horizon = get_forecast_horizon(res) + base_power = get_model_base_power(sim_results) + results_by_key = + Dict{OptimizationContainerKey, ResultsByTime{DenseAxisArray{Float64, 2}}}() + model_name = Symbol(get_model_name(sim_results)) + resolution = get_resolution(sim_results) + for key in container_keys - _results = SortedDict{Dates.DateTime, DataFrames.DataFrame}() + results_by_time = ResultsByTime( + key, + SortedDict{Dates.DateTime, DenseAxisArray{Float64, 2}}(), + resolution, + get_column_names(store, DecisionModelIndexType, model_name, key), + ) for ts in timestamps - out = read_result(DataFrames.DataFrame, store, model_name, key, ts) + array = read_result(DenseAxisArray, store, model_name, key, ts) if convert_result_to_natural_units(key) - out .*= base_power + array.data .*= base_power end - if size(out, 1) == horizon - time_col = range(ts; length = horizon, step = resolution) - DataFrames.insertcols!(out, 1, :DateTime => time_col) - else - @warn( - "$(encode_key_as_string(key)) has a different horizon than the problem specification. Can't assign Time stamps to the resulting DataFrame." - ) + results_by_time[ts] = array + end + results_by_key[key] = results_by_time + end + + return results_by_key +end + +function _get_store_value( + ::Type{Matrix{Float64}}, + sim_results::SimulationProblemResults{DecisionModelSimulationResults}, + container_keys::Vector{<:OptimizationContainerKey}, + timestamps, + store::SimulationStore, +) + base_power = get_model_base_power(sim_results) + results_by_key = Dict{OptimizationContainerKey, ResultsByTime{Matrix{Float64}}}() + model_name = Symbol(get_model_name(sim_results)) + resolution = get_resolution(sim_results) + + for key in container_keys + results_by_time = ResultsByTime{Matrix{Float64}}( + key, + SortedDict{Dates.DateTime, Matrix{Float64}}(), + resolution, + get_column_names(store, DecisionModelIndexType, model_name, key), + ) + for ts in timestamps + array = read_result(Array, store, model_name, key, ts) + if convert_result_to_natural_units(key) + array .*= base_power end - _results[ts] = out + results_by_time[ts] = array end - results[key] = _results + results_by_key[key] = results_by_time end - return results + return results_by_key end function _process_timestamps( @@ -139,27 +218,28 @@ function _process_timestamps( return requested_range end -function _read_variables( +function _read_results( + ::Type{T}, res::SimulationProblemResults{DecisionModelSimulationResults}, - variable_keys, + result_keys, timestamps, - store, -) - isempty(variable_keys) && return FieldResultsByTime() + store::Union{Nothing, <:SimulationStore}, +) where {T <: Union{Matrix{Float64}, DenseAxisArray{Float64, 2}}} + isempty(result_keys) && return Dict{OptimizationContainerKey, ResultsByTime{T}}() + if store === nothing && res.store !== nothing # In this case we have an InMemorySimulationStore. store = res.store end - _validate_keys(keys(get_variables(res)), variable_keys) - same_timestamps = isempty(setdiff(res.results_timestamps, timestamps)) - keys_with_values = [k for (k, v) in get_variables(res) if !isempty(v)] - same_keys = isempty([n for n in variable_keys if n ∉ keys_with_values]) - if same_timestamps && same_keys - @debug "reading variables from SimulationsResults" - vals = filter(p -> (p.first ∈ variable_keys), get_variables(res)) + existing_keys = list_result_keys(res, first(result_keys)) + _validate_keys(existing_keys, result_keys) + cached_results = get_cached_results(res, first(result_keys)) + if _are_results_cached(res, result_keys, timestamps, keys(cached_results)) + @debug "reading results from SimulationsResults cache" + vals = Dict(k => cached_results[k] for k in result_keys) else - @debug "reading variables from data store" - vals = _get_store_value(res, variable_keys, timestamps, store) + @debug "reading results from data store" + vals = _get_store_value(T, res, result_keys, timestamps, store) end return vals end @@ -191,27 +271,9 @@ function read_variable( ) key = _deserialize_key(VariableKey, res, args...) timestamps = _process_timestamps(res, initial_time, count) - return _read_variables(res, [key], timestamps, store)[key] -end - -function _read_duals(res::SimulationProblemResults, dual_keys, timestamps, store) - isempty(dual_keys) && return FieldResultsByTime() - if store === nothing && res.store !== nothing - # In this case we have an InMemorySimulationStore. - store = res.store - end - _validate_keys(keys(get_duals(res)), dual_keys) - same_timestamps = isempty(setdiff(res.results_timestamps, timestamps)) - keys_with_values = [k for (k, v) in get_duals(res) if !isempty(v)] - same_keys = isempty([n for n in dual_keys if n ∉ keys_with_values]) - if same_timestamps && same_keys - @debug "reading duals from SimulationsResults" - vals = filter(p -> (p.first ∈ dual_keys), get_duals(res)) - else - @debug "reading duals from data store" - vals = _get_store_value(res, dual_keys, timestamps, store) - end - return vals + return make_dataframes( + _read_results(DenseAxisArray{Float64, 2}, res, [key], timestamps, store)[key], + ) end """ @@ -234,27 +296,9 @@ function read_dual( ) key = _deserialize_key(ConstraintKey, res, args...) timestamps = _process_timestamps(res, initial_time, count) - return _read_duals(res, [key], timestamps, store)[key] -end - -function _read_parameters(res::SimulationProblemResults, parameter_keys, timestamps, store) - isempty(parameter_keys) && return FieldResultsByTime() - if store === nothing && res.store !== nothing - # In this case we have an InMemorySimulationStore. - store = res.store - end - _validate_keys(keys(get_parameters(res)), parameter_keys) - same_timestamps = isempty(setdiff(res.results_timestamps, timestamps)) - parameters_with_values = [k for (k, v) in get_parameters(res) if !isempty(v)] - same_parameters = isempty([n for n in parameter_keys if n ∉ parameters_with_values]) - if same_timestamps && same_parameters - @debug "reading parameters from SimulationsResults" - vals = filter(p -> (p.first ∈ parameter_keys), get_parameters(res)) - else - @debug "reading parameters from data store" - vals = _get_store_value(res, parameter_keys, timestamps, store) - end - return vals + return make_dataframes( + _read_results(DenseAxisArray{Float64, 2}, res, [key], timestamps, store)[key], + ) end """ @@ -270,39 +314,15 @@ Return the values for the requested parameter. It keeps requests when performing function read_parameter( res::SimulationProblemResults{DecisionModelSimulationResults}, args...; - time_series_name = nothing, initial_time::Union{Nothing, Dates.DateTime} = nothing, count::Union{Int, Nothing} = nothing, store = nothing, ) key = _deserialize_key(ParameterKey, res, args...) timestamps = _process_timestamps(res, initial_time, count) - return _read_parameters(res, [key], timestamps, store)[key] -end - -function _read_aux_variables( - res::SimulationProblemResults, - aux_variable_keys, - timestamps, - store, -) - isempty(aux_variable_keys) && return FieldResultsByTime() - if store === nothing && res.store !== nothing - # In this case we have an InMemorySimulationStore. - store = res.store - end - _validate_keys(keys(get_aux_variables(res)), aux_variable_keys) - same_timestamps = isempty(setdiff(res.results_timestamps, timestamps)) - keys_with_values = [k for (k, v) in get_aux_variables(res) if !isempty(v)] - same_keys = isempty([n for n in aux_variable_keys if n ∉ keys_with_values]) - if same_timestamps && same_keys - @debug "reading aux variables from SimulationsResults" - vals = filter(p -> (p.first ∈ aux_variable_keys), get_aux_variables(res)) - else - @debug "reading aux variables from data store" - vals = _get_store_value(res, aux_variable_keys, timestamps, store) - end - return vals + return make_dataframes( + _read_results(DenseAxisArray{Float64, 2}, res, [key], timestamps, store)[key], + ) end """ @@ -318,39 +338,15 @@ Return the values for the requested auxillary variables. It keeps requests when function read_aux_variable( res::SimulationProblemResults{DecisionModelSimulationResults}, args...; - time_series_name = nothing, initial_time::Union{Nothing, Dates.DateTime} = nothing, count::Union{Int, Nothing} = nothing, store = nothing, ) key = _deserialize_key(AuxVarKey, res, args...) timestamps = _process_timestamps(res, initial_time, count) - return _read_aux_variables(res, [key], timestamps, store)[key] -end - -function _read_expressions( - res::SimulationProblemResults, - expression_keys, - timestamps, - store, -) - isempty(expression_keys) && return FieldResultsByTime() - if store === nothing && res.store !== nothing - # In this case we have an InMemorySimulationStore. - store = res.store - end - _validate_keys(keys(get_expressions(res)), expression_keys) - same_timestamps = isempty(setdiff(res.results_timestamps, timestamps)) - keys_with_values = [k for (k, v) in get_expressions(res) if !isempty(v)] - same_keys = isempty([n for n in expression_keys if n ∉ keys_with_values]) - if same_timestamps && same_keys - @debug "reading expressions from SimulationsResults" - vals = filter(p -> (p.first ∈ expression_keys), get_expressions(res)) - else - @debug "reading expressions from data store" - vals = _get_store_value(res, expression_keys, timestamps, store) - end - return vals + return make_dataframes( + _read_results(DenseAxisArray{Float64, 2}, res, [key], timestamps, store)[key], + ) end """ @@ -366,14 +362,15 @@ Return the values for the requested auxillary variables. It keeps requests when function read_expression( res::SimulationProblemResults{DecisionModelSimulationResults}, args...; - time_series_name = nothing, initial_time::Union{Nothing, Dates.DateTime} = nothing, count::Union{Int, Nothing} = nothing, store = nothing, ) key = _deserialize_key(ExpressionKey, res, args...) timestamps = _process_timestamps(res, initial_time, count) - return _read_expressions(res, [key], timestamps, store)[key] + return make_dataframes( + _read_results(DenseAxisArray{Float64, 2}, res, [key], timestamps, store)[key], + ) end function get_realized_timestamps( @@ -407,64 +404,26 @@ function get_realized_timestamps( return requested_range end -function read_variables_with_keys( +function read_results_with_keys( res::SimulationProblemResults{DecisionModelSimulationResults}, - variables::Vector{<:OptimizationContainerKey}; + result_keys::Vector{<:OptimizationContainerKey}; start_time::Union{Nothing, Dates.DateTime} = nothing, len::Union{Int, Nothing} = nothing, ) meta = RealizedMeta(res; start_time = start_time, len = len) timestamps = _process_timestamps(res, meta.start_time, meta.len) - result_values = _read_variables(res, variables, timestamps, nothing) + result_values = _read_results(Matrix{Float64}, res, result_keys, timestamps, nothing) return get_realization(result_values, meta) end -function read_parameters_with_keys( +function _are_results_cached( res::SimulationProblemResults{DecisionModelSimulationResults}, - parameters::Vector{<:OptimizationContainerKey}; - start_time::Union{Nothing, Dates.DateTime} = nothing, - len::Union{Int, Nothing} = nothing, -) - meta = RealizedMeta(res; start_time = start_time, len = len) - timestamps = _process_timestamps(res, meta.start_time, meta.len) - result_values = _read_parameters(res, parameters, timestamps, nothing) - return get_realization(result_values, meta) -end - -function read_duals_with_keys( - res::SimulationProblemResults{DecisionModelSimulationResults}, - duals::Vector{<:OptimizationContainerKey}; - start_time::Union{Nothing, Dates.DateTime} = nothing, - len::Union{Int, Nothing} = nothing, -) - meta = RealizedMeta(res; start_time = start_time, len = len) - timestamps = _process_timestamps(res, meta.start_time, meta.len) - result_values = _read_duals(res, duals, timestamps, nothing) - return get_realization(result_values, meta) -end - -function read_aux_variables_with_keys( - res::SimulationProblemResults, - aux_variables::Vector{<:OptimizationContainerKey}; - start_time::Union{Nothing, Dates.DateTime} = nothing, - len::Union{Int, Nothing} = nothing, -) - meta = RealizedMeta(res; start_time = start_time, len = len) - timestamps = _process_timestamps(res, meta.start_time, meta.len) - result_values = _read_aux_variables(res, aux_variables, timestamps, nothing) - return get_realization(result_values, meta) -end - -function read_expressions_with_keys( - res::SimulationProblemResults{DecisionModelSimulationResults}, - expressions::Vector{<:OptimizationContainerKey}; - start_time::Union{Nothing, Dates.DateTime} = nothing, - len::Union{Int, Nothing} = nothing, + output_keys, + timestamps, + cached_keys, ) - meta = RealizedMeta(res; start_time = start_time, len = len) - timestamps = _process_timestamps(res, meta.start_time, meta.len) - result_values = _read_expressions(res, expressions, timestamps, nothing) - return get_realization(result_values, meta) + return isempty(setdiff(timestamps, res.results_timestamps)) && + isempty(setdiff(output_keys, cached_keys)) end """ @@ -497,9 +456,7 @@ function load_results!( expressions = Vector{Tuple}(), ) initial_time = initial_time === nothing ? first(get_timestamps(res)) : initial_time - res.results_timestamps = _process_timestamps(res, initial_time, count) - dual_keys = [_deserialize_key(ConstraintKey, res, x...) for x in duals] parameter_keys = [_deserialize_key(ParameterKey, res, x...) for x in parameters] variable_keys = [_deserialize_key(VariableKey, res, x...) for x in variables] @@ -507,21 +464,54 @@ function load_results!( expression_keys = [_deserialize_key(ExpressionKey, res, x...) for x in expressions] function merge_results(store) merge!( - get_variables(res), - _read_variables(res, variable_keys, res.results_timestamps, store), + get_cached_variables(res), + _read_results( + DenseAxisArray{Float64, 2}, + res, + variable_keys, + res.results_timestamps, + store, + ), + ) + merge!( + get_cached_duals(res), + _read_results( + DenseAxisArray{Float64, 2}, + res, + dual_keys, + res.results_timestamps, + store, + ), ) - merge!(get_duals(res), _read_duals(res, dual_keys, res.results_timestamps, store)) merge!( - get_parameters(res), - _read_parameters(res, parameter_keys, res.results_timestamps, store), + get_cached_parameters(res), + _read_results( + DenseAxisArray{Float64, 2}, + res, + parameter_keys, + res.results_timestamps, + store, + ), ) merge!( - get_aux_variables(res), - _read_aux_variables(res, aux_variable_keys, res.results_timestamps, store), + get_cached_aux_variables(res), + _read_results( + DenseAxisArray{Float64, 2}, + res, + aux_variable_keys, + res.results_timestamps, + store, + ), ) merge!( - get_expressions(res), - _read_expressions(res, expression_keys, res.results_timestamps, store), + get_cached_expressions(res), + _read_results( + DenseAxisArray{Float64, 2}, + res, + expression_keys, + res.results_timestamps, + store, + ), ) end diff --git a/src/simulation/emulation_model_simulation_results.jl b/src/simulation/emulation_model_simulation_results.jl index 628831898a..a84cb125a2 100644 --- a/src/simulation/emulation_model_simulation_results.jl +++ b/src/simulation/emulation_model_simulation_results.jl @@ -17,12 +17,6 @@ function SimulationProblemResults( container_key_lookup; kwargs..., ) - variables = list_emulation_model_keys(store, STORE_CONTAINER_VARIABLES) - parameters = list_emulation_model_keys(store, STORE_CONTAINER_PARAMETERS) - duals = list_emulation_model_keys(store, STORE_CONTAINER_DUALS) - aux_variables = list_emulation_model_keys(store, STORE_CONTAINER_AUX_VARIABLES) - expressions = list_emulation_model_keys(store, STORE_CONTAINER_EXPRESSIONS) - return SimulationProblemResults{EmulationModelSimulationResults}( store, model_name, @@ -30,19 +24,81 @@ function SimulationProblemResults( sim_params, path, EmulationModelSimulationResults( - Dict(x => DataFrames.DataFrame() for x in variables), - Dict(x => DataFrames.DataFrame() for x in duals), - Dict(x => DataFrames.DataFrame() for x in parameters), - Dict(x => DataFrames.DataFrame() for x in aux_variables), - Dict(x => DataFrames.DataFrame() for x in expressions), + Dict( + x => DataFrames.DataFrame() for + x in list_emulation_model_keys(store, STORE_CONTAINER_VARIABLES) + ), + Dict( + x => DataFrames.DataFrame() for + x in list_emulation_model_keys(store, STORE_CONTAINER_DUALS) + ), + Dict( + x => DataFrames.DataFrame() for + x in list_emulation_model_keys(store, STORE_CONTAINER_PARAMETERS) + ), + Dict( + x => DataFrames.DataFrame() for + x in list_emulation_model_keys(store, STORE_CONTAINER_AUX_VARIABLES) + ), + Dict( + x => DataFrames.DataFrame() for + x in list_emulation_model_keys(store, STORE_CONTAINER_EXPRESSIONS) + ), container_key_lookup, ); kwargs..., ) end +list_aux_variable_keys(res::SimulationProblemResults{EmulationModelSimulationResults}) = + collect(keys(res.values.aux_variables)) +list_dual_keys(res::SimulationProblemResults{EmulationModelSimulationResults}) = + collect(keys(res.values.duals)) +list_expression_keys(res::SimulationProblemResults{EmulationModelSimulationResults}) = + collect(keys(res.values.expressions)) +list_parameter_keys(res::SimulationProblemResults{EmulationModelSimulationResults}) = + collect(keys(res.values.parameters)) +list_variable_keys(res::SimulationProblemResults{EmulationModelSimulationResults}) = + collect(keys(res.values.variables)) + +get_cached_aux_variables(res::SimulationProblemResults{EmulationModelSimulationResults}) = + res.values.aux_variables +get_cached_duals(res::SimulationProblemResults{EmulationModelSimulationResults}) = + res.values.duals +get_cached_expressions(res::SimulationProblemResults{EmulationModelSimulationResults}) = + res.values.expressions +get_cached_parameters(res::SimulationProblemResults{EmulationModelSimulationResults}) = + res.values.parameters +get_cached_variables(res::SimulationProblemResults{EmulationModelSimulationResults}) = + res.values.variables + +get_cached_results( + res::SimulationProblemResults{EmulationModelSimulationResults}, + ::AuxVarKey, +) = get_cached_aux_variables(res) +get_cached_results( + res::SimulationProblemResults{EmulationModelSimulationResults}, + ::ConstraintKey, +) = get_cached_duals(res) +get_cached_results( + res::SimulationProblemResults{EmulationModelSimulationResults}, + ::ExpressionKey, +) = get_cached_expressions(res) +get_cached_results( + res::SimulationProblemResults{EmulationModelSimulationResults}, + ::ParameterKey, +) = get_cached_parameters(res) +get_cached_results( + res::SimulationProblemResults{EmulationModelSimulationResults}, + ::VariableKey, +) = get_cached_variables(res) + +function _list_containers(res::SimulationProblemResults) + return (getfield(res.values, x) for x in get_container_fields(res)) +end + function Base.empty!(res::SimulationProblemResults{EmulationModelSimulationResults}) - for container in _get_containers(res) + for container in _list_containers(res) for df in values(container) empty!(df) end @@ -50,7 +106,7 @@ function Base.empty!(res::SimulationProblemResults{EmulationModelSimulationResul end function Base.isempty(res::SimulationProblemResults{EmulationModelSimulationResults}) - for container in _get_containers(res) + for container in _list_containers(res) for df in values(container) if !isempty(df) return false @@ -63,7 +119,7 @@ end function Base.length(res::SimulationProblemResults{EmulationModelSimulationResults}) count_not_empty = 0 - for container in _get_containers(res) + for container in _list_containers(res) for df in values(container) if !isempty(df) count_not_empty += 1 @@ -99,10 +155,14 @@ function _get_store_value( for key in container_keys start_time, _len, resolution = _check_offsets(res, key, store, start_time, len) start_index = (start_time - first(res.timestamps)) ÷ resolution + 1 - df = read_results(store, key; index = start_index, len = _len) + array = read_results(store, key; index = start_index, len = _len) if convert_result_to_natural_units(key) - df .*= base_power + array.data .*= base_power end + # PERF: this is a double-permutedims with HDF + # We could make an optimized version of this that reads Arrays + # like decision_model_simulation_results + df = DataFrames.DataFrame(permutedims(array.data), axes(array)[1]) time_col = range(start_time; length = _len, step = res.resolution) DataFrames.insertcols!(df, 1, :DateTime => time_col) results[key] = df @@ -120,7 +180,7 @@ function _check_offsets( ) dataset_size = get_emulation_model_dataset_size(store, key) resolution = - (last(res.timestamps) - first(res.timestamps) + res.resolution) ÷ dataset_size[1] + (last(res.timestamps) - first(res.timestamps) + res.resolution) ÷ dataset_size if isnothing(start_time) start_time = first(res.timestamps) elseif start_time < first(res.timestamps) || start_time > last(res.timestamps) @@ -150,40 +210,33 @@ function _check_offsets( return start_time, len, resolution end -function read_aux_variables_with_keys( - res::SimulationProblemResults{EmulationModelSimulationResults}, - aux_variables::Vector{<:OptimizationContainerKey}; - start_time::Union{Nothing, Dates.DateTime} = nothing, - len::Union{Nothing, Int} = nothing, -) - return _read_aux_variables(res, aux_variables, nothing, start_time, len) -end - -function _read_aux_variables( +function _read_results( res::SimulationProblemResults{EmulationModelSimulationResults}, - aux_variable_keys, - store, + result_keys, + store; start_time = nothing, len = nothing, ) - isempty(aux_variable_keys) && - return Dict{OptimizationContainerKey, DataFrames.DataFrame}() + isempty(result_keys) && return Dict{OptimizationContainerKey, DataFrames.DataFrame}() if store === nothing && res.store !== nothing # In this case we have an InMemorySimulationStore. store = res.store end - _validate_keys(keys(get_aux_variables(res)), aux_variable_keys) - keys_with_values = Set((k for (k, v) in get_aux_variables(res) if !isempty(v))) - if isempty(setdiff(aux_variable_keys, keys_with_values)) + existing_keys = list_result_keys(res, first(result_keys)) + _validate_keys(existing_keys, result_keys) + cached_results = Dict( + k => v for (k, v) in get_cached_results(res, first(result_keys)) if !isempty(v) + ) + if isempty(setdiff(result_keys, keys(cached_results))) @debug "reading aux_variables from SimulationsResults" - vals = filter(p -> (p.first ∈ aux_variable_keys), get_aux_variables(res)) + vals = Dict(k => cached_results[k] for k in result_keys) else @debug "reading aux_variables from data store" vals = _get_store_value( res, - aux_variable_keys, + result_keys, store; start_time = start_time, len = len, @@ -192,150 +245,13 @@ function _read_aux_variables( return vals end -function _read_expressions( - res::SimulationProblemResults{EmulationModelSimulationResults}, - expression_keys, - store, - start_time = nothing, - len = nothing, -) - isempty(expression_keys) && - return Dict{OptimizationContainerKey, DataFrames.DataFrame}() - if store === nothing && res.store !== nothing - # In this case we have an InMemorySimulationStore. - store = res.store - end - - _validate_keys(keys(get_expressions(res)), expression_keys) - keys_with_values = Set((k for (k, v) in get_expressions(res) if !isempty(v))) - if isempty(setdiff(expression_keys, keys_with_values)) - @debug "reading expressions from SimulationsResults" - vals = filter(p -> (p.first ∈ expression_keys), get_expressions(res)) - else - @debug "reading expressions from data store" - vals = _get_store_value( - res, - expression_keys, - store; - start_time = start_time, - len = len, - ) - end - return vals -end - -function read_duals_with_keys( +function read_results_with_keys( res::SimulationProblemResults{EmulationModelSimulationResults}, - duals::Vector{<:OptimizationContainerKey}; + result_keys::Vector{<:OptimizationContainerKey}; start_time::Union{Nothing, Dates.DateTime} = nothing, len::Union{Nothing, Int} = nothing, ) - return _read_duals(res, duals, nothing, start_time, len) -end - -function _read_duals( - res::SimulationProblemResults{EmulationModelSimulationResults}, - dual_keys, - store, - start_time = nothing, - len = nothing, -) - isempty(dual_keys) && return Dict{OptimizationContainerKey, DataFrames.DataFrame}() - if store === nothing && res.store !== nothing - # In this case we have an InMemorySimulationStore. - store = res.store - end - - _validate_keys(keys(get_duals(res)), dual_keys) - keys_with_values = Set((k for (k, v) in get_duals(res) if !isempty(v))) - if isempty(setdiff(dual_keys, keys_with_values)) - @debug "reading duals from SimulationsResults" - vals = filter(p -> (p.first ∈ dual_keys), get_duals(res)) - else - @debug "reading duals from data store" - vals = _get_store_value(res, dual_keys, store; start_time = start_time, len = len) - end - return vals -end - -function read_expressions_with_keys( - res::SimulationProblemResults{EmulationModelSimulationResults}, - expressions::Vector{<:OptimizationContainerKey}; - start_time::Union{Nothing, Dates.DateTime} = nothing, - len::Union{Nothing, Int} = nothing, -) - return _read_expressions(res, expressions, nothing, start_time, len) -end - -function read_parameters_with_keys( - res::SimulationProblemResults{EmulationModelSimulationResults}, - parameters::Vector{<:OptimizationContainerKey}; - start_time::Union{Nothing, Dates.DateTime} = nothing, - len::Union{Nothing, Int} = nothing, -) - return _read_parameters(res, parameters, nothing, start_time, len) -end - -function _read_parameters( - res::SimulationProblemResults{EmulationModelSimulationResults}, - parameter_keys, - store, - start_time = nothing, - len = nothing, -) - isempty(parameter_keys) && return Dict{OptimizationContainerKey, DataFrames.DataFrame}() - if store === nothing && res.store !== nothing - # In this case we have an InMemorySimulationStore. - store = res.store - end - - _validate_keys(keys(get_parameters(res)), parameter_keys) - keys_with_values = Set((k for (k, v) in get_parameters(res) if !isempty(v))) - if isempty(setdiff(parameter_keys, keys_with_values)) - @debug "reading parameters from SimulationsResults" - vals = filter(p -> (p.first ∈ parameter_keys), get_parameters(res)) - else - @debug "reading parameters from data store" - vals = - _get_store_value(res, parameter_keys, store; start_time = start_time, len = len) - end - return vals -end - -function read_variables_with_keys( - res::SimulationProblemResults{EmulationModelSimulationResults}, - variables::Vector{<:OptimizationContainerKey}; - start_time::Union{Nothing, Dates.DateTime} = nothing, - len::Union{Nothing, Int} = nothing, -) - return _read_variables(res, variables, nothing, start_time, len) -end - -function _read_variables( - res::SimulationProblemResults{EmulationModelSimulationResults}, - variable_keys, - store, - start_time = nothing, - len = nothing, -) - isempty(variable_keys) && return Dict{OptimizationContainerKey, DataFrames.DataFrame}() - if store === nothing && res.store !== nothing - # In this case we have an InMemorySimulationStore. - store = res.store - end - - _validate_keys(keys(get_variables(res)), variable_keys) - keys_with_values = Set((k for (k, v) in get_variables(res) if !isempty(v))) - if isempty(setdiff(variable_keys, keys_with_values)) - @debug "reading variables from SimulationsResults" - # TODO: This needs to filter by start_time and len. - vals = filter(p -> (p.first ∈ variable_keys), get_variables(res)) - else - @debug "reading variables from data store" - vals = - _get_store_value(res, variable_keys, store; start_time = start_time, len = len) - end - return vals + return _read_results(res, result_keys, nothing; start_time = start_time, len = len) end """ @@ -344,7 +260,8 @@ overwrites the previously loaded results. This is useful when loading results fr locations over network connections. For each variable/parameter/dual, etc., each element must be the name encoded as a string, -like `"ActivePowerVariable__ThermalStandard"`` or a Tuple with its constituent types, like `(ActivePowerVariable, ThermalStandard)`. +like `"ActivePowerVariable__ThermalStandard"`` or a Tuple with its constituent types, like +`(ActivePowerVariable, ThermalStandard)`. # Arguments @@ -369,11 +286,11 @@ function load_results!( parameter_keys = [_deserialize_key(ParameterKey, res, x...) for x in parameters] variable_keys = [_deserialize_key(VariableKey, res, x...) for x in variables] function merge_results(store) - merge!(get_aux_variables(res), _read_aux_variables(res, aux_variable_keys, store)) - merge!(get_duals(res), _read_duals(res, dual_keys, store)) - merge!(get_expressions(res), _read_expressions(res, expression_keys, store)) - merge!(get_parameters(res), _read_parameters(res, parameter_keys, store)) - merge!(get_variables(res), _read_variables(res, variable_keys, store)) + merge!(get_cached_aux_variables(res), _read_results(res, aux_variable_keys, store)) + merge!(get_cached_duals(res), _read_results(res, dual_keys, store)) + merge!(get_cached_expressions(res), _read_results(res, expression_keys, store)) + merge!(get_cached_parameters(res), _read_results(res, parameter_keys, store)) + merge!(get_cached_variables(res), _read_results(res, variable_keys, store)) end if res.store isa InMemorySimulationStore diff --git a/src/simulation/hdf_simulation_store.jl b/src/simulation/hdf_simulation_store.jl index 12a8ff18eb..efa9e70a05 100644 --- a/src/simulation/hdf_simulation_store.jl +++ b/src/simulation/hdf_simulation_store.jl @@ -175,12 +175,12 @@ function list_decision_model_keys( container_type::Symbol, ) container = getfield(get_dm_data(store)[model], container_type) - return keys(container) + return collect(keys(container)) end function list_emulation_model_keys(store::HdfSimulationStore, container_type::Symbol) container = getfield(get_em_data(store), container_type) - return keys(container) + return collect(keys(container)) end function write_optimizer_stats!( @@ -345,7 +345,7 @@ function read_result( if (ndims(data) < 2 || size(data)[1] == 1) && size(data)[2] != size(columns)[1] data = reshape(data, length(data), 1) end - return DataFrames.DataFrame(data, columns) + return DataFrames.DataFrame(data, collect(columns); copycols = false) end function read_result( @@ -355,23 +355,29 @@ function read_result( key::OptimizationContainerKey, index::Union{DecisionModelIndexType, EmulationModelIndexType}, ) - data, columns = _read_data_columns(store, model_name, key, index) + if is_cached(store.cache, model_name, key, index) + data = read_result(store.cache, model_name, key, index) + columns = get_column_names(store, DecisionModelIndexType, model_name, key) + else + data, columns = _read_result(store, model_name, key, index) + end return DenseAxisArray(permutedims(data), columns, 1:size(data)[1]) end function read_result( - ::Type{<:Array}, + ::Type{Array}, store::HdfSimulationStore, model_name::Symbol, key::OptimizationContainerKey, index::Union{DecisionModelIndexType, EmulationModelIndexType}, ) if is_cached(store.cache, model_name, key, index) - data = _read_result(store.cache, model_name, key, index) + data = read_result(store.cache, model_name, key, index) else - # PERF: If this will be commonly used then we need to remove reading of columns. data, _ = _read_result(store, model_name, key, index) end + + return data end function read_results( @@ -392,7 +398,28 @@ function read_results( end columns = get_column_names(key, dataset) @assert_op size(data)[2] == length(columns) - return DataFrames.DataFrame(data, columns) + return DenseAxisArray(permutedims(data), columns, 1:size(data)[1]) +end + +function get_column_names( + store::HdfSimulationStore, + ::Type{DecisionModelIndexType}, + model_name::Symbol, + key::OptimizationContainerKey, +) + !isopen(store) && throw(ArgumentError("store must be opened prior to reading")) + dataset = _get_dm_dataset(store, model_name, key) + return get_column_names(key, dataset) +end + +function get_column_names( + store::HdfSimulationStore, + ::Type{EmulationModelIndexType}, + key::OptimizationContainerKey, +) + !isopen(store) && throw(ArgumentError("store must be opened prior to reading")) + dataset = _get_em_dataset(store, key) + return get_column_names(key, dataset) end function get_emulation_model_dataset_size( @@ -400,12 +427,12 @@ function get_emulation_model_dataset_size( key::OptimizationContainerKey, ) dataset = _get_em_dataset(store, key) - return size(dataset.values) + return size(dataset.values)[1] end function _read_result( store::HdfSimulationStore, - model_name::Symbol, + ::Symbol, key::OptimizationContainerKey, index::EmulationModelIndexType, ) diff --git a/src/simulation/in_memory_simulation_store.jl b/src/simulation/in_memory_simulation_store.jl index 467b5fe1ff..cff3ef5b60 100644 --- a/src/simulation/in_memory_simulation_store.jl +++ b/src/simulation/in_memory_simulation_store.jl @@ -129,10 +129,9 @@ function initialize_problem_storage!( for problem in keys(store.params.decision_models_params) get_dm_data(store)[problem] = DecisionModelStore() for type in STORE_CONTAINERS - for (key, reqs) in getfield(dm_problem_reqs[problem], type) + for (key, _) in getfield(dm_problem_reqs[problem], type) container = getfield(get_dm_data(store)[problem], type) - container[key] = - OrderedDict{Dates.DateTime, DatasetContainer{DataFrameDataset}}() + container[key] = OrderedDict{Dates.DateTime, DenseAxisArray{Float64}}() store.container_key_lookup[encode_key_as_string(key)] = key @debug "Added $type $key in $problem" _group = LOG_GROUP_SIMULATION_STORE end @@ -142,9 +141,10 @@ function initialize_problem_storage!( for type in STORE_CONTAINERS for (key, reqs) in getfield(em_problem_reqs, type) container = get_data_field(get_em_data(store), type) - container[key] = DataFrameDataset( - DataFrames.DataFrame( - OrderedDict(c => fill(NaN, reqs["dims"][1]) for c in reqs["columns"]), + container[key] = InMemoryDataset( + fill!( + DenseAxisArray{Float64}(undef, reqs["columns"], 1:reqs["dims"][1]), + NaN, ), ) store.container_key_lookup[encode_key_as_string(key)] = key @@ -155,8 +155,26 @@ function initialize_problem_storage!( return end +function get_column_names( + store::InMemorySimulationStore, + ::Type{DecisionModelIndexType}, + model_name::Symbol, + key::OptimizationContainerKey, +) + return get_column_names(get_dm_data(store)[model_name], key) +end + +function get_column_names( + store::InMemorySimulationStore, + ::Type{EmulationModelIndexType}, + model_name::Symbol, + key::OptimizationContainerKey, +) + return get_column_names(get_em_data(store)[model_name], key) +end + function read_result( - ::Type{DataFrames.DataFrame}, + ::Type{DenseAxisArray}, store::InMemorySimulationStore, model_name::Symbol, key::OptimizationContainerKey, @@ -166,7 +184,19 @@ function read_result( end function read_result( - ::Type{DataFrames.DataFrame}, + ::Type{Array}, + store::InMemorySimulationStore, + model_name::Symbol, + key::OptimizationContainerKey, + index::DecisionModelIndexType, +) + return permutedims( + read_results(get_dm_data(store)[model_name], key; index = index).data, + ) +end + +function read_result( + ::Type{DenseAxisArray}, store::InMemorySimulationStore, ::Symbol, key::OptimizationContainerKey, @@ -188,7 +218,7 @@ function get_emulation_model_dataset_size( store::InMemorySimulationStore, key::OptimizationContainerKey, ) - return get_dataset_size(get_em_data(store), key) + return get_dataset_size(get_em_data(store), key)[2] end # Note that this function is not type-stable. diff --git a/src/simulation/realized_meta.jl b/src/simulation/realized_meta.jl index ff54983c6e..e0344146fe 100644 --- a/src/simulation/realized_meta.jl +++ b/src/simulation/realized_meta.jl @@ -47,41 +47,48 @@ function RealizedMeta( end function get_realization( - result_values::Dict{ - OptimizationContainerKey, - SortedDict{Dates.DateTime, DataFrames.DataFrame}, - }, + results::Dict{OptimizationContainerKey, ResultsByTime{Matrix{Float64}}}, meta::RealizedMeta, ) realized_values = Dict{OptimizationContainerKey, DataFrames.DataFrame}() - for (key, result_value) in result_values - results_concat = Dict{Symbol, Vector{Float64}}() - for (step, (t, df)) in enumerate(result_value) + lk = ReentrantLock() + num_rows = length(meta.realized_timestamps) + start = time() + Threads.@threads for key in collect(keys(results)) + results_by_time = results[key] + columns = get_column_names(results_by_time) + num_cols = length(columns) + matrix = Matrix{Float64}(undef, num_rows, num_cols) + for (step, (_, array)) in enumerate(results_by_time) first_id = step > 1 ? 1 : meta.start_offset last_id = step == meta.len ? meta.interval_len - meta.end_offset : meta.interval_len - if last_id - first_id > size(df, 1) + if last_id - first_id > size(array, 1) error( - "Variable $(encode_key_as_string(key)) has $(size(df, 1)) number of steps, that is different than the default problem horizon. \ + "Variable $(encode_key_as_string(key)) has $(size(array, 1)) number of steps, that is different than the default problem horizon. \ Can't calculate the realized variables. Use `read_variables` instead and write your own concatenation", ) end - for colname in propertynames(df) - colname == :DateTime && continue - col = df[!, colname][first_id:last_id] - if !haskey(results_concat, colname) - results_concat[colname] = col - else - results_concat[colname] = vcat(results_concat[colname], col) - end - end + row_start = (step - 1) * meta.interval_len + 1 + row_end = row_start + last_id - first_id + matrix[row_start:row_end, :] = array[first_id:last_id, :] end - realized_values[key] = DataFrames.DataFrame(results_concat; copycols = false) + df = DataFrames.DataFrame(matrix, collect(columns); copycols = false) DataFrames.insertcols!( - realized_values[key], + df, 1, :DateTime => meta.realized_timestamps, ) + lock(lk) do + realized_values[key] = df + end end + + duration = time() - start + if Threads.nthreads() == 1 && duration > 10.0 + @info "Time to read results: $duration seconds. You will likely get faster " * + "results by starting Julia with multiple threads." + end + return realized_values end diff --git a/src/simulation/simulation.jl b/src/simulation/simulation.jl index 2cd14d7a4a..0b2985a9ec 100644 --- a/src/simulation/simulation.jl +++ b/src/simulation/simulation.jl @@ -771,7 +771,7 @@ function _update_simulation_state!(sim::Simulation, model::DecisionModel) for field in fieldnames(DatasetContainer) for key in list_decision_model_keys(store, model_name, field) !has_dataset(get_decision_states(state), key) && continue - res = read_result(DataFrames.DataFrame, store, model_name, key, simulation_time) + res = read_result(DenseAxisArray, store, model_name, key, simulation_time) update_decision_state!(state, key, res, simulation_time, model_params) end end diff --git a/src/simulation/simulation_problem_results.jl b/src/simulation/simulation_problem_results.jl index 981716d5dc..5d0cf565e2 100644 --- a/src/simulation/simulation_problem_results.jl +++ b/src/simulation/simulation_problem_results.jl @@ -1,13 +1,11 @@ -const ResultsByTime = SortedDict{Dates.DateTime, DataFrames.DataFrame} -const FieldResultsByTime = Dict{OptimizationContainerKey, ResultsByTime} - abstract type OperationModelSimulationResults end # Subtypes need to implement the following methods for SimulationProblemResults{T} -# - read_aux_variables_with_keys -# - read_variables_with_keys -# - read_parameters_with_keys -# - read_duals_with_keys -# - read_expressions_with_keys +# - read_results_with_keys +# - list_aux_variable_keys +# - list_dual_keys +# - list_expression_keys +# - list_parameter_keys +# - list_variable_keys # - load_results! """ @@ -71,68 +69,41 @@ IS.get_timestamp(result::SimulationProblemResults) = result.results_timestamps get_interval(res::SimulationProblemResults) = res.timestamps.step IS.get_base_power(result::SimulationProblemResults) = result.base_power -# Subtypes can override if they don't have these fields. -get_aux_variables(res::SimulationProblemResults) = res.values.aux_variables -get_duals(res::SimulationProblemResults) = res.values.duals -get_expressions(res::SimulationProblemResults) = res.values.expressions -get_parameters(res::SimulationProblemResults) = res.values.parameters -get_variables(res::SimulationProblemResults) = res.values.variables +list_result_keys(res::SimulationProblemResults, ::AuxVarKey) = list_aux_variable_keys(res) +list_result_keys(res::SimulationProblemResults, ::ConstraintKey) = list_dual_keys(res) +list_result_keys(res::SimulationProblemResults, ::ExpressionKey) = list_expression_keys(res) +list_result_keys(res::SimulationProblemResults, ::ParameterKey) = list_parameter_keys(res) +list_result_keys(res::SimulationProblemResults, ::VariableKey) = list_variable_keys(res) """ Return an array of variable names (strings) that are available for reads. """ list_variable_names(res::SimulationProblemResults) = - encode_keys_as_strings(keys(get_variables(res))) + encode_keys_as_strings(list_variable_keys(res)) """ Return an array of dual names (strings) that are available for reads. """ list_dual_names(res::SimulationProblemResults) = - encode_keys_as_strings(keys(get_duals(res))) + encode_keys_as_strings(list_dual_keys(res)) """ Return an array of parmater names (strings) that are available for reads. """ list_parameter_names(res::SimulationProblemResults) = - encode_keys_as_strings(keys(get_parameters(res))) + encode_keys_as_strings(list_parameter_keys(res)) """ Return an array of auxillary variable names (strings) that are available for reads. """ list_aux_variable_names(res::SimulationProblemResults) = - encode_keys_as_strings(keys(get_aux_variables(res))) + encode_keys_as_strings(list_aux_variable_keys(res)) """ Return an array of expression names (strings) that are available for reads. """ list_expression_names(res::SimulationProblemResults) = - encode_keys_as_strings(keys(get_expressions(res))) - -""" -Return an array of VariableKeys that are available for reads. -""" -list_variable_keys(res::SimulationProblemResults) = collect(keys(get_variables(res))) - -""" -Return an array of ConstraintKeys that are available for reading duals. -""" -list_dual_keys(res::SimulationProblemResults) = collect(keys(get_duals(res))) - -""" -Return an array of ParameterKeys that are available for reads. -""" -list_parameter_keys(res::SimulationProblemResults) = collect(keys(get_parameters(res))) - -""" -Return an array of AuxVarKeys that are available for reads. -""" -list_aux_variable_keys(res::SimulationProblemResults) = - collect(keys(get_aux_variables(res))) - -""" -Return an array of ExpressionKeys that are available for reads. -""" -list_expression_keys(res::SimulationProblemResults) = collect(keys(get_expressions(res))) + encode_keys_as_strings(list_expression_keys(res)) """ Return a reference to a StepRange of available timestamps. @@ -205,23 +176,13 @@ function _deserialize_key( return make_key(T, args...) end -function _get_containers(x::SimulationProblemResults) - return ( - get_aux_variables(x), - get_duals(x), - get_expressions(x), - get_parameters(x), - get_variables(x), - ) -end +get_container_fields(x::SimulationProblemResults) = + (:aux_variables, :duals, :expressions, :parameters, :variables) -function _validate_keys(existing_keys, container_keys) - existing = Set(existing_keys) - for key in container_keys - if key ∉ existing - @error "$key is not stored", existing_keys - throw(IS.InvalidValue("$key is not stored")) - end +function _validate_keys(existing_keys, result_keys) + diff = setdiff(result_keys, existing_keys) + if !isempty(diff) + throw(IS.InvalidValue("These keys are not stored: $diff")) end return end @@ -236,6 +197,9 @@ Emulation problem results are returned in a Dict{String, DataFrame}. Limit the data sizes returned by specifying `initial_time` and `count` for decision problems or `start_time` and `len` for emulation problems. +If the Julia process is started with multiple threads, the code will read the variables in +parallel. + See also [`load_results!`](@ref) to preload data into memory. # Arguments @@ -251,7 +215,7 @@ See also [`load_results!`](@ref) to preload data into memory. # Examples -```julia-repl +```julia julia > variables_as_strings = ["ActivePowerVariable__ThermalStandard", "ActivePowerVariable__RenewableDispatch"] julia > variables_as_types = @@ -261,7 +225,7 @@ julia > read_realized_variables(results, variables_as_types) ``` """ function read_realized_variables(res::SimulationProblemResults; kwargs...) - return read_realized_variables(res, collect(keys(get_variables(res))); kwargs...) + return read_realized_variables(res, list_variable_keys(res); kwargs...) end function read_realized_variables( @@ -289,7 +253,7 @@ function read_realized_variables( variables::Vector{<:OptimizationContainerKey}; kwargs..., ) - result_values = read_variables_with_keys(res, variables; kwargs...) + result_values = read_results_with_keys(res, variables; kwargs...) return Dict(encode_key_as_string(k) => v for (k, v) in result_values) end @@ -318,7 +282,7 @@ See also [`load_results!`](@ref) to preload data into memory. # Examples -```julia-repl +```julia julia > read_realized_variable(results, "ActivePowerVariable__ThermalStandard") julia > read_realized_variable(results, (ActivePowerVariable, ThermalStandard)) ``` @@ -348,12 +312,12 @@ end """ Return the final values for the requested auxiliary variables for each time step for a problem. -Refer to [`read_realized_variables`](@ref) for help and examples. +Refer to [`read_realized_aux_variables`](@ref) for help and examples. """ function read_realized_aux_variables(res::SimulationProblemResults; kwargs...) return read_realized_aux_variables( res, - collect(keys(get_aux_variables(res))); + list_aux_variable_keys(res); kwargs..., ) end @@ -387,7 +351,7 @@ function read_realized_aux_variables( aux_variables::Vector{<:OptimizationContainerKey}; kwargs..., ) - result_values = read_aux_variables_with_keys(res, aux_variables; kwargs...) + result_values = read_results_with_keys(res, aux_variables; kwargs...) return Dict(encode_key_as_string(k) => v for (k, v) in result_values) end @@ -419,7 +383,7 @@ function read_realized_aux_variable( ) return first( values( - read_realized_aux_variables(res, [aux_variableKey(aux_variable...)]; kwargs...), + read_realized_aux_variables(res, [AuxVarKey(aux_variable...)]; kwargs...), ), ) end @@ -427,10 +391,10 @@ end """ Return the final values for the requested parameters for each time step for a problem. -Refer to [`read_realized_variables`](@ref) for help and examples. +Refer to [`read_realized_parameters`](@ref) for help and examples. """ function read_realized_parameters(res::SimulationProblemResults; kwargs...) - return read_realized_parameters(res, collect(keys(get_parameters(res))); kwargs...) + return read_realized_parameters(res, list_parameter_keys(res); kwargs...) end function read_realized_parameters( @@ -462,7 +426,7 @@ function read_realized_parameters( parameters::Vector{<:OptimizationContainerKey}; kwargs..., ) - result_values = read_parameters_with_keys(res, parameters; kwargs...) + result_values = read_results_with_keys(res, parameters; kwargs...) return Dict(encode_key_as_string(k) => v for (k, v) in result_values) end @@ -496,10 +460,10 @@ end """ Return the final values for the requested duals for each time step for a problem. -Refer to [`read_realized_variables`](@ref) for help and examples. +Refer to [`read_realized_duals`](@ref) for help and examples. """ function read_realized_duals(res::SimulationProblemResults; kwargs...) - return read_realized_duals(res, collect(keys(get_duals(res))); kwargs...) + return read_realized_duals(res, list_dual_keys(res); kwargs...) end function read_realized_duals( @@ -527,7 +491,7 @@ function read_realized_duals( duals::Vector{<:OptimizationContainerKey}; kwargs..., ) - result_values = read_duals_with_keys(res, duals; kwargs...) + result_values = read_results_with_keys(res, duals; kwargs...) return Dict(encode_key_as_string(k) => v for (k, v) in result_values) end @@ -555,10 +519,10 @@ end """ Return the final values for the requested expressions for each time step for a problem. -Refer to [`read_realized_variables`](@ref) for help and examples. +Refer to [`read_realized_expressions`](@ref) for help and examples. """ function read_realized_expressions(res::SimulationProblemResults; kwargs...) - return read_realized_expressions(res, collect(keys(get_expressions(res))); kwargs...) + return read_realized_expressions(res, list_expression_keys(res); kwargs...) end function read_realized_expressions( @@ -590,7 +554,7 @@ function read_realized_expressions( expressions::Vector{<:OptimizationContainerKey}; kwargs..., ) - result_values = read_expressions_with_keys(res, expressions; kwargs...) + result_values = read_results_with_keys(res, expressions; kwargs...) return Dict(encode_key_as_string(k) => v for (k, v) in result_values) end @@ -667,21 +631,25 @@ function export_realized_results( if !isdir(save_path) throw(IS.ConflictingInputsError("Specified path is not valid.")) end - write_data(read_variables_with_keys(res, list_variable_keys(res)), save_path) + write_data(read_results_with_keys(res, list_variable_keys(res)), save_path) !isempty(list_dual_keys(res)) && - write_data(read_duals_with_keys(res, list_dual_keys(res)), save_path; name = "dual") + write_data( + read_results_with_keys(res, list_dual_keys(res)), + save_path; + name = "dual", + ) !isempty(list_parameter_keys(res)) && write_data( - read_parameters_with_keys(res, list_parameter_keys(res)), + read_results_with_keys(res, list_parameter_keys(res)), save_path; name = "parameter", ) !isempty(list_aux_variable_keys(res)) && write_data( - read_aux_variables_with_keys(res, list_aux_variable_keys(res)), + read_results_with_keys(res, list_aux_variable_keys(res)), save_path; name = "aux_variable", ) !isempty(list_expression_keys(res)) && write_data( - read_expressions_with_keys(res, list_expression_keys(res)), + read_results_with_keys(res, list_expression_keys(res)), save_path; name = "expression", ) diff --git a/src/simulation/simulation_results.jl b/src/simulation/simulation_results.jl index 6bffc75725..7cbfa5b53c 100644 --- a/src/simulation/simulation_results.jl +++ b/src/simulation/simulation_results.jl @@ -12,10 +12,6 @@ function check_folder_integrity(folder::String) return false end -function _fill_result_value_container(fields) - return FieldResultsByTime(x => ResultsByTime() for x in fields) -end - struct SimulationResults path::String params::SimulationStoreParams diff --git a/src/simulation/simulation_state.jl b/src/simulation/simulation_state.jl index a4caea1160..021c9a2518 100644 --- a/src/simulation/simulation_state.jl +++ b/src/simulation/simulation_state.jl @@ -1,16 +1,16 @@ struct SimulationState current_time::Base.RefValue{Dates.DateTime} last_decision_model::Base.RefValue{Symbol} - decision_states::DatasetContainer{DataFrameDataset} - system_states::DatasetContainer{DataFrameDataset} + decision_states::DatasetContainer{InMemoryDataset} + system_states::DatasetContainer{InMemoryDataset} end function SimulationState() return SimulationState( Ref(UNSET_INI_TIME), Ref(:None), - DatasetContainer{DataFrameDataset}(), - DatasetContainer{DataFrameDataset}(), + DatasetContainer{InMemoryDataset}(), + DatasetContainer{InMemoryDataset}(), ) end @@ -89,10 +89,10 @@ function _initialize_model_states!( value_counts = params[key].horizon ÷ params[key].resolution column_names = get_column_names(key, value) if !haskey(field_states, key) || length(field_states[key]) < value_counts - field_states[key] = DataFrameDataset( - DataFrames.DataFrame( - fill(NaN, value_counts, length(column_names)), - column_names, + field_states[key] = InMemoryDataset( + fill!( + DenseAxisArray{Float64}(undef, column_names, 1:value_counts), + NaN, ), collect( range( @@ -125,7 +125,7 @@ function _initialize_system_states!( emulator_states, key, make_system_state( - DataFrames.DataFrame(cols .=> NaN), + fill!(DenseAxisArray{Float64}(undef, cols, 1:1), NaN), simulation_initial_time, min_res, ), @@ -153,7 +153,7 @@ function _initialize_system_states!( emulator_states, key, make_system_state( - DataFrames.DataFrame(column_names .=> NaN), + fill!(DenseAxisArray{Float64}(undef, column_names, 1:1), NaN), simulation_initial_time, get_resolution(emulation_model), ), @@ -173,7 +173,7 @@ function _initialize_system_states!( emulator_states, key, make_system_state( - DataFrames.DataFrame(cols .=> NaN), + fill!(DenseAxisArray{Float64}(undef, cols, 1:1), NaN), simulation_initial_time, get_resolution(emulation_model), ), @@ -207,11 +207,12 @@ end function update_decision_state!( state::SimulationState, key::OptimizationContainerKey, - store_data::DataFrames.DataFrame, + store_data::DenseAxisArray{Float64}, simulation_time::Dates.DateTime, model_params::ModelStoreParams, ) state_data = get_decision_state_data(state, key) + column_names = get_column_names(state_data) model_resolution = get_resolution(model_params) state_resolution = get_data_resolution(state_data) resolution_ratio = model_resolution ÷ state_resolution @@ -227,13 +228,13 @@ function update_decision_state!( end offset = resolution_ratio - 1 - result_time_index = axes(store_data)[1] + result_time_index = axes(store_data)[2] set_update_timestamp!(state_data, simulation_time) for t in result_time_index state_range = state_data_index:(state_data_index + offset) - for name in DataFrames.names(store_data), i in state_range + for name in column_names, i in state_range # TODO: We could also interpolate here - state_data.values[i, name] = store_data[t, name] + state_data.values[name, i] = store_data[name, t] end set_last_recorded_row!(state_data, state_range[end]) state_data_index += resolution_ratio @@ -244,7 +245,7 @@ end function update_decision_state!( state::SimulationState, key::AuxVarKey{EnergyOutput, T}, - store_data::DataFrames.DataFrame, + store_data::DenseAxisArray{Float64}, simulation_time::Dates.DateTime, model_params::ModelStoreParams, ) where {T <: PSY.Component} @@ -264,12 +265,13 @@ function update_decision_state!( end offset = resolution_ratio - 1 - result_time_index = axes(store_data)[1] + result_time_index = axes(store_data)[2] set_update_timestamp!(state_data, simulation_time) + column_names = axes(state_data.values)[1] for t in result_time_index state_range = state_data_index:(state_data_index + offset) - for name in DataFrames.names(store_data), i in state_range - state_data.values[i, name] = store_data[t, name] / resolution_ratio + for name in column_names, i in state_range + state_data.values[name, i] = store_data[name, t] / resolution_ratio end set_last_recorded_row!(state_data, state_range[end]) state_data_index += resolution_ratio @@ -281,7 +283,7 @@ end function update_decision_state!( state::SimulationState, key::AuxVarKey{S, T}, - store_data::DataFrames.DataFrame, + store_data::DenseAxisArray{Float64}, simulation_time::Dates.DateTime, model_params::ModelStoreParams, ) where {T <: PSY.Component, S <: Union{TimeDurationOff, TimeDurationOn}} @@ -300,7 +302,7 @@ function update_decision_state!( end offset = resolution_ratio - 1 - result_time_index = axes(store_data)[1] + result_time_index = axes(store_data)[2] set_update_timestamp!(state_data, simulation_time) if resolution_ratio == 1.0 @@ -311,16 +313,17 @@ function update_decision_state!( error("Incorrect Problem Resolution specification") end + column_names = axes(state_data.values)[1] for t in result_time_index state_range = state_data_index:(state_data_index + offset) @assert_op state_range[end] <= length(state_data) - for name in DataFrames.names(store_data), i in state_range + for name in column_names, i in state_range if t == 1 && i == 1 - state_data.values[i, name] = store_data[t, name] * resolution_ratio + state_data.values[name, i] = store_data[name, t] * resolution_ratio else - state_data.values[i, name] = - if store_data[t, name] > 0 - state_data.values[i - 1, name] + increment_per_period + state_data.values[name, i] = + if store_data[name, t] > 0 + state_data.values[name, i - 1] + increment_per_period else 0 end @@ -354,11 +357,11 @@ function get_system_state_data(state::SimulationState, key::OptimizationContaine end function get_system_state_value(state::SimulationState, key::OptimizationContainerKey) - return get_dataset_values(get_system_states(state), key)[1, :] + return get_dataset_values(get_system_states(state), key)[:, 1] end function update_system_state!( - state::DatasetContainer{DataFrameDataset}, + state::DatasetContainer{InMemoryDataset}, key::OptimizationContainerKey, store::SimulationStore, model_name::Symbol, @@ -366,7 +369,7 @@ function update_system_state!( ) em_data = get_em_data(store) ix = get_last_recorded_row(em_data, key) - res = read_result(DataFrames.DataFrame, store, model_name, key, ix) + res = read_result(DenseAxisArray, store, model_name, key, ix) dataset = get_dataset(state, key) set_update_timestamp!(dataset, simulation_time) set_dataset_values!(state, key, 1, res) @@ -375,9 +378,9 @@ function update_system_state!( end function update_system_state!( - state::DatasetContainer{DataFrameDataset}, + state::DatasetContainer{InMemoryDataset}, key::OptimizationContainerKey, - decision_state::DatasetContainer{DataFrameDataset}, + decision_state::DatasetContainer{InMemoryDataset}, simulation_time::Dates.DateTime, ) decision_dataset = get_dataset(decision_state, key) @@ -409,9 +412,9 @@ function update_system_state!( end function update_system_state!( - state::DatasetContainer{DataFrameDataset}, + state::DatasetContainer{InMemoryDataset}, key::AuxVarKey{T, PSY.ThermalStandard}, - decision_state::DatasetContainer{DataFrameDataset}, + decision_state::DatasetContainer{InMemoryDataset}, simulation_time::Dates.DateTime, ) where {T <: Union{TimeDurationOn, TimeDurationOff}} decision_dataset = get_dataset(decision_state, key) diff --git a/src/utils/dataframes_utils.jl b/src/utils/dataframes_utils.jl index b36f5366ce..3dfadcadd3 100644 --- a/src/utils/dataframes_utils.jl +++ b/src/utils/dataframes_utils.jl @@ -7,20 +7,20 @@ Creates a DataFrame from a JuMP DenseAxisArray or SparseAxisArray. - `array`: JuMP DenseAxisArray or SparseAxisArray to convert - `key::OptimizationContainerKey`: """ -function axis_array_to_dataframe(array::DenseAxisArray, key::OptimizationContainerKey) +function to_dataframe(array::DenseAxisArray, key::OptimizationContainerKey) return DataFrames.DataFrame(to_matrix(array), get_column_names(key, array)) end -function axis_array_to_dataframe(array::SparseAxisArray, key::OptimizationContainerKey) +function to_dataframe(array::SparseAxisArray, key::OptimizationContainerKey) return DataFrames.DataFrame(to_matrix(array), get_column_names(key, array)) end -function axis_array_to_dataframe(array::Matrix{Float64}, key::OptimizationContainerKey) +function to_dataframe(array::Matrix{Float64}, key::OptimizationContainerKey) return DataFrames.DataFrame(array, get_column_names(key, array)) end function to_matrix(df::DataFrames.DataFrame) - return Matrix{Float64}(vals) + return Matrix{Float64}(df) end function to_matrix(df_row::DataFrames.DataFrameRow{DataFrames.DataFrame, DataFrames.Index}) diff --git a/src/utils/jump_utils.jl b/src/utils/jump_utils.jl index 16d6b498b2..22ee166e56 100644 --- a/src/utils/jump_utils.jl +++ b/src/utils/jump_utils.jl @@ -28,7 +28,7 @@ function jump_value(input::JuMP.ConstraintRef)::Float64 return JuMP.dual(input) end -function jump_value(input::Float64)::Float64 +function jump_value(input::Float64) return input end @@ -42,41 +42,11 @@ function fix_parameter_value(input::JuMP.VariableRef, value::Float64) end function to_matrix(array::DenseAxisArray{T, 1, K}) where {T, K <: NTuple{1, Any}} - data = jump_value.(array.data) - data = reshape(data, length(data), 1) - return data -end - -function to_matrix(array::DenseAxisArray{T, 1, K}) where {T <: Real, K <: NTuple{1, Any}} - data = reshape(deepcopy(array.data), length(array.data), 1) - return data -end - -function to_matrix(array::DenseAxisArray{T, 2, K}) where {T, K <: NTuple{2, Any}} - ax = axes(array) - data = Matrix{Float64}(undef, length(ax[2]), length(ax[1])) - for t in ax[2], (ix, name) in enumerate(ax[1]) - data[t, ix] = jump_value(array[name, t]) - end - return data -end - -function to_matrix( - array::DenseAxisArray{T, 2, K}, -) where {T <: Vector{Tuple{Float64, Float64}}, K <: NTuple{2, Any}} - ax = axes(array) - data = Matrix{Vector{Tuple{Float64, Float64}}}(undef, length(ax[2]), length(ax[1])) - for t in ax[2], (ix, name) in enumerate(ax[1]) - data[t, ix] = jump_value(array[name, t]) - end - return data + data = array.data[:] + return reshape(data, length(data), 1) end -# to_matrix functions are used to convert JuMP.Containers to matrices that can be written into -# HDF5 Store. -function to_matrix(array::DenseAxisArray{T, 2, K}) where {T <: Real, K <: NTuple{2, Any}} - return deepcopy(permutedims(array.data)) -end +to_matrix(array::DenseAxisArray{T, 2} where {T}) = permutedims(array.data) function to_matrix(::DenseAxisArray{T, N, K}) where {T, N, K <: NTuple{N, Any}} error( @@ -132,7 +102,7 @@ function _to_matrix( timesteps = Set{Int}(k[N] for k in keys(array.data)) data = Matrix{Float64}(undef, length(timesteps), length(columns)) for (ix, col) in enumerate(columns), t in timesteps - data[t, ix] = jump_value(array.data[(col..., t)]) + data[t, ix] = array.data[(col..., t)] end return data end @@ -148,7 +118,7 @@ function to_dataframe(array::SparseAxisArray{T, N, K}) where {T, N, K <: NTuple{ return DataFrames.DataFrame(_to_matrix(array, columns), columns) end -to_matrix(array::Array) = array +to_matrix(array::Matrix) = array """ Returns the correct container specification for the selected type of JuMP Model diff --git a/test/test_simulation_build.jl b/test/test_simulation_build.jl index 5bda0fa750..1d78fc1a92 100644 --- a/test/test_simulation_build.jl +++ b/test/test_simulation_build.jl @@ -39,10 +39,10 @@ ed_vars = [ActivePowerVariable] for (key, data) in state.decision_states.variables if PSI.get_entry_type(key) ∈ uc_vars - count, _ = size(data.values) + _, count = size(data.values) @test count == 24 elseif PSI.get_entry_type(key) ∈ ed_vars - count, _ = size(data.values) + _, count = size(data.values) @test count == 288 end end diff --git a/test/test_simulation_results.jl b/test/test_simulation_results.jl index 4b8816d043..6de5cafbae 100644 --- a/test/test_simulation_results.jl +++ b/test/test_simulation_results.jl @@ -417,10 +417,16 @@ function test_decision_problem_results_values( ) @test !isempty( - results_ed.values.variables[PSI.VariableKey(ActivePowerVariable, ThermalStandard)], + PSI.get_cached_variables(results_ed)[PSI.VariableKey( + ActivePowerVariable, + ThermalStandard, + )].data, ) @test length( - results_ed.values.variables[PSI.VariableKey(ActivePowerVariable, ThermalStandard)], + PSI.get_cached_variables(results_ed)[PSI.VariableKey( + ActivePowerVariable, + ThermalStandard, + )].data, ) == 3 @test length(results_ed) == 3 @@ -447,8 +453,9 @@ function test_decision_problem_results_values( ) empty!(results_ed) - @test isempty( - results_ed.values.variables[PSI.VariableKey(ActivePowerVariable, ThermalStandard)], + @test !haskey( + PSI.get_cached_variables(results_ed), + PSI.VariableKey(ActivePowerVariable, ThermalStandard), ) initial_time = DateTime("2024-01-01T00:00:00") @@ -462,18 +469,24 @@ function test_decision_problem_results_values( ) @test !isempty( - results_ed.values.variables[PSI.VariableKey(ActivePowerVariable, ThermalStandard)], + PSI.get_cached_variables(results_ed)[PSI.VariableKey( + ActivePowerVariable, + ThermalStandard, + )].data, ) @test !isempty( - results_ed.values.duals[PSI.ConstraintKey(CopperPlateBalanceConstraint, System)], + PSI.get_cached_duals(results_ed)[PSI.ConstraintKey( + CopperPlateBalanceConstraint, + System, + )].data, ) @test !isempty( - results_ed.values.parameters[PSI.ParameterKey{ + PSI.get_cached_parameters(results_ed)[PSI.ParameterKey{ ActivePowerTimeSeriesParameter, RenewableDispatch, }( "", - )], + )].data, ) end diff --git a/test/test_utils.jl b/test/test_utils.jl index 3709dbf639..5d49df15cf 100644 --- a/test/test_utils.jl +++ b/test/test_utils.jl @@ -8,35 +8,35 @@ end end @testset "Axis Array to DataFrame" begin - # The axis_array_to_dataframe test the use of the `to_matrix` and `get_column_names` methods + # The to_dataframe test the use of the `to_matrix` and `get_column_names` methods one = PSI.DenseAxisArray{Float64}(undef, 1:2) fill!(one, 1.0) mock_key = PSI.VariableKey(ActivePowerVariable, ThermalStandard) - one_df = PSI.axis_array_to_dataframe(one, mock_key) + one_df = PSI.to_dataframe(one, mock_key) test_df = DataFrames.DataFrame(PSI.encode_key(mock_key) => [1.0, 1.0]) @test one_df == test_df two = PSI.DenseAxisArray{Float64}(undef, [:a], 1:2) fill!(two, 1.0) - two_df = PSI.axis_array_to_dataframe(two, mock_key) + two_df = PSI.to_dataframe(two, mock_key) test_df = DataFrames.DataFrame(:a => [1.0, 1.0]) @test two_df == test_df three = PSI.DenseAxisArray{Float64}(undef, [:a], 1:2, 1:3) - @test_throws ErrorException PSI.axis_array_to_dataframe(three, mock_key) + @test_throws ErrorException PSI.to_dataframe(three, mock_key) four = PSI.DenseAxisArray{Float64}(undef, [:a], 1:2, 1:3, 1:5) - @test_throws ErrorException PSI.axis_array_to_dataframe(four, mock_key) + @test_throws ErrorException PSI.to_dataframe(four, mock_key) sparse_num = JuMP.Containers.@container([i = 1:10, j = (i + 1):10, t = 1:24], 0.0 + i + j + t) - @test_throws MethodError PSI.axis_array_to_dataframe(sparse_num, mock_key) + @test_throws MethodError PSI.to_dataframe(sparse_num, mock_key) i_num = 1:10 j_vals = Dict("$i" => string.((i + 1):11) for i in i_num) sparse_valid = JuMP.Containers.@container([i = string.(i_num), j = j_vals[i], t = 1:24], rand()) - df = PSI.axis_array_to_dataframe(sparse_valid, mock_key) + df = PSI.to_dataframe(sparse_valid, mock_key) @test size(df) == (24, 55) end From 9d358bb7ceda07d3cfca15d0659035ca98f0d966 Mon Sep 17 00:00:00 2001 From: Daniel Thom Date: Mon, 7 Aug 2023 15:32:46 -0600 Subject: [PATCH 240/370] Use get_num_rows instead of length --- src/core/dataset.jl | 6 +----- src/core/store_common.jl | 4 ---- src/parameters/update_parameters.jl | 6 +++--- src/simulation/simulation_state.jl | 22 +++++++++++++++++----- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/core/dataset.jl b/src/core/dataset.jl index be87fb6fc4..0ccc71e488 100644 --- a/src/core/dataset.jl +++ b/src/core/dataset.jl @@ -59,7 +59,7 @@ function InMemoryDataset(values::DenseAxisArray{Float64, 2}) ) end -Base.length(s::InMemoryDataset) = size(s.values)[2] +get_num_rows(s::InMemoryDataset) = size(s.values)[2] function make_system_state( values::DenseAxisArray{Float64, 2}, @@ -141,10 +141,6 @@ mutable struct HDF5Dataset <: AbstractDataset end end -#Base.length(s::HDF5Dataset) = size(s.values)[1] # TODO DT: what about the 3-dim case? -# Not getting called by tests -Base.length(s::HDF5Dataset) = error("die") - HDF5Dataset(values, column_dataset, resolution, initial_time) = HDF5Dataset( values, diff --git a/src/core/store_common.jl b/src/core/store_common.jl index 9f29279d7c..cde24a94d5 100644 --- a/src/core/store_common.jl +++ b/src/core/store_common.jl @@ -96,11 +96,7 @@ function write_model_parameter_results!( should_export_parameter(export_params[:exports], index, model_name, key) resolution = export_params[:resolution] file_type = export_params[:file_type] - # TODO DT: why was jump_value being called again? - # (first time was in calculate_parameter_values) - # Was it always a noop? df = to_dataframe(data, key) - #df = to_dataframe(jump_value.(data), key) time_col = range(index; length = horizon, step = resolution) DataFrames.insertcols!(df, 1, :DateTime => time_col) export_result(file_type, exports_path, key, index, df) diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index ef942d3ee4..d951a9c1b8 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -175,7 +175,7 @@ function _update_parameter_values!( state_data = get_dataset(state, get_attribute_key(attributes)) state_timestamps = state_data.timestamps - max_state_index = length(state_data) + max_state_index = get_num_rows(state_data) state_data_index = find_timestamp_index(state_timestamps, current_time) sim_timestamps = range(current_time; step = resolution, length = time[end]) @@ -215,7 +215,7 @@ function _update_parameter_values!( state_data = get_dataset(state, get_attribute_key(attributes)) state_timestamps = state_data.timestamps - max_state_index = length(state_data) + max_state_index = get_num_rows(state_data) state_data_index = find_timestamp_index(state_timestamps, current_time) @@ -409,7 +409,7 @@ function update_parameter_values!( interval_time_steps = Int(get_interval(model.internal.store_parameters) / resolution) state_data = get_dataset(input, get_attribute_key(parameter_attributes)) state_timestamps = state_data.timestamps - max_state_index = length(state_data) + max_state_index = get_num_rows(state_data) state_data_index = find_timestamp_index(state_timestamps, current_time) sim_timestamps = range(current_time; step = resolution, length = time[end]) diff --git a/src/simulation/simulation_state.jl b/src/simulation/simulation_state.jl index 021c9a2518..daaa02fcfa 100644 --- a/src/simulation/simulation_state.jl +++ b/src/simulation/simulation_state.jl @@ -88,7 +88,7 @@ function _initialize_model_states!( !should_write_resulting_value(key) && continue value_counts = params[key].horizon ÷ params[key].resolution column_names = get_column_names(key, value) - if !haskey(field_states, key) || length(field_states[key]) < value_counts + if !haskey(field_states, key) || get_num_rows(field_states[key]) < value_counts field_states[key] = InMemoryDataset( fill!( DenseAxisArray{Float64}(undef, column_names, 1:value_counts), @@ -222,7 +222,11 @@ function update_decision_state!( if simulation_time > get_end_of_step_timestamp(state_data) state_data_index = 1 state_data.timestamps[:] .= - range(simulation_time; step = state_resolution, length = length(state_data)) + range( + simulation_time; + step = state_resolution, + length = get_num_rows(state_data), + ) else state_data_index = find_timestamp_index(state_timestamps, simulation_time) end @@ -259,7 +263,11 @@ function update_decision_state!( if simulation_time > get_end_of_step_timestamp(state_data) state_data_index = 1 state_data.timestamps[:] .= - range(simulation_time; step = state_resolution, length = length(state_data)) + range( + simulation_time; + step = state_resolution, + length = get_num_rows(state_data), + ) else state_data_index = find_timestamp_index(state_timestamps, simulation_time) end @@ -296,7 +304,11 @@ function update_decision_state!( if simulation_time > get_end_of_step_timestamp(state_data) state_data_index = 1 state_data.timestamps[:] .= - range(simulation_time; step = state_resolution, length = length(state_data)) + range( + simulation_time; + step = state_resolution, + length = get_num_rows(state_data), + ) else state_data_index = find_timestamp_index(state_data.timestamps, simulation_time) end @@ -316,7 +328,7 @@ function update_decision_state!( column_names = axes(state_data.values)[1] for t in result_time_index state_range = state_data_index:(state_data_index + offset) - @assert_op state_range[end] <= length(state_data) + @assert_op state_range[end] <= get_num_rows(state_data) for name in column_names, i in state_range if t == 1 && i == 1 state_data.values[name, i] = store_data[name, t] * resolution_ratio From be0bae0505a2831cf0563cf3c028e726ca838418 Mon Sep 17 00:00:00 2001 From: Daniel Thom Date: Mon, 7 Aug 2023 15:33:06 -0600 Subject: [PATCH 241/370] Add type specification --- src/simulation/hdf_simulation_store.jl | 5 ++--- test/test_simulation_store.jl | 19 ++++++++++++++----- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/simulation/hdf_simulation_store.jl b/src/simulation/hdf_simulation_store.jl index efa9e70a05..508f7e6b1a 100644 --- a/src/simulation/hdf_simulation_store.jl +++ b/src/simulation/hdf_simulation_store.jl @@ -519,10 +519,9 @@ function write_result!( key::OptimizationContainerKey, index::DecisionModelIndexType, ::Dates.DateTime, - data, -) + data::DenseAxisArray{Float64, N, K}, +) where {N, K <: NTuple{N, Any}} output_cache = get_output_cache(store.cache, model_name, key) - cur_size = get_size(store.cache) add_result!(output_cache, index, to_matrix(data), is_full(store.cache, cur_size)) diff --git a/test/test_simulation_store.jl b/test/test_simulation_store.jl index ec6a7a4524..5a29a38d35 100644 --- a/test/test_simulation_store.jl +++ b/test/test_simulation_store.jl @@ -74,18 +74,28 @@ end function _run_sim_test(path, sim, variables, model_defs, cache_rules, seed) rng = MersenneTwister(seed) - type = STORE_CONTAINER_VARIABLES open_store(HdfSimulationStore, path, "w") do store sim_time = sim["initial_time"] _initialize!(store, sim, variables, model_defs, cache_rules) - for step in 1:sim["num_steps"] + for _ in 1:sim["num_steps"] for model in keys(model_defs) model_time = sim_time for i in 1:model_defs[model]["execution_count"] for key in keys(variables) data = rand(rng, size(model_defs[model]["variables"][key])...) - write_result!(store, model, key, model_time, model_time, data) columns = model_defs[model]["names"] + write_result!( + store, + model, + key, + model_time, + model_time, + Containers.DenseAxisArray( + permutedims(data), + columns, + 1:size(data)[1], + ), + ) _verify_data(data, store, model, key, model_time, columns) end @@ -111,10 +121,9 @@ end function _verify_read_results(path, sim, variables, model_defs, seed) rng = MersenneTwister(seed) - type = STORE_CONTAINER_VARIABLES open_store(HdfSimulationStore, path, "r") do store sim_time = sim["initial_time"] - for step in 1:sim["num_steps"] + for _ in 1:sim["num_steps"] for model in keys(model_defs) model_time = sim_time for i in 1:model_defs[model]["execution_count"] From 0c2bd8222578ec6817670ed73c8e749928e8305d Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 8 Aug 2023 10:03:28 -0600 Subject: [PATCH 242/370] add correction to lb --- src/devices_models/devices/thermal_generation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/devices/thermal_generation.jl b/src/devices_models/devices/thermal_generation.jl index bafed666f6..b58d01f965 100644 --- a/src/devices_models/devices/thermal_generation.jl +++ b/src/devices_models/devices/thermal_generation.jl @@ -34,7 +34,7 @@ get_variable_upper_bound(::ReactivePowerVariable, d::PSY.ThermalGen, ::AbstractT ############## OnVariable, ThermalGen #################### get_variable_binary(::OnVariable, ::Type{<:PSY.ThermalGen}, ::AbstractThermalFormulation) = true get_variable_warm_start_value(::OnVariable, d::PSY.ThermalGen, ::AbstractThermalFormulation) = PSY.get_status(d) ? 1.0 : 0.0 -get_variable_lower_bound(::ActivePowerVariable, d::PSY.ThermalGen, ::AbstractThermalUnitCommitment) = PSY.get_must_run(d) ? 1.0 : 0.0 +get_variable_lower_bound(::OnVariable, d::PSY.ThermalGen, ::AbstractThermalUnitCommitment) = PSY.get_must_run(d) ? 1.0 : 0.0 ############## StopVariable, ThermalGen #################### get_variable_binary(::StopVariable, ::Type{<:PSY.ThermalGen}, ::AbstractThermalFormulation) = true From 727ad178afb1e3fcf0de6dd143b8f9f056e34f15 Mon Sep 17 00:00:00 2001 From: Daniel Thom Date: Tue, 8 Aug 2023 11:37:14 -0600 Subject: [PATCH 243/370] Throw error on invalid function call --- src/core/dataset.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/core/dataset.jl b/src/core/dataset.jl index 0ccc71e488..6340551e1f 100644 --- a/src/core/dataset.jl +++ b/src/core/dataset.jl @@ -167,13 +167,13 @@ function get_last_updated_timestamp(s::HDF5Dataset) end function get_value_timestamp(s::HDF5Dataset, date::Dates.DateTime) + error("Not implemented for HDF5Dataset. Required if it is used for simulation state.") # TODO: This code is broken because timestamps is not a field. - # The function is called for InMemoryDataset but not HDF5Dataset. - s_index = find_timestamp_index(s.timestamps, date) - if isnothing(s_index) - error("Request time stamp $date not in the state") - end - return s.initial_timestamp + s.resolution * (s_index - 1) + #s_index = find_timestamp_index(s.timestamps, date) + #if isnothing(s_index) + # error("Request time stamp $date not in the state") + #end + #return s.initial_timestamp + s.resolution * (s_index - 1) end function set_value!(s::HDF5Dataset, vals, index::Int) From e12bf6c20e6a40cceff700a04ea52fbbeb9182b1 Mon Sep 17 00:00:00 2001 From: Daniel Thom Date: Tue, 8 Aug 2023 11:37:42 -0600 Subject: [PATCH 244/370] Add types to functions --- src/core/results_by_time.jl | 14 +++++++++++--- src/operation/problem_results.jl | 4 ++-- .../decision_model_simulation_results.jl | 10 +++++----- src/simulation/hdf_simulation_store.jl | 6 +++--- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/core/results_by_time.jl b/src/core/results_by_time.jl index 70b99a5e01..4dc2405410 100644 --- a/src/core/results_by_time.jl +++ b/src/core/results_by_time.jl @@ -12,7 +12,7 @@ end function _check_column_consistency( data::SortedDict{Dates.DateTime, DenseAxisArray{Float64, 2}}, - cols, + cols::Vector{String}, ) for val in values(data) if axes(val)[1] != cols @@ -21,7 +21,10 @@ function _check_column_consistency( end end -function _check_column_consistency(data::SortedDict{Dates.DateTime, Matrix{Float64}}, cols) +function _check_column_consistency( + data::SortedDict{Dates.DateTime, Matrix{Float64}}, + cols::Vector{String}, +) for val in values(data) if size(val)[2] != length(cols) error("Mismatch in length of Matrix columns: $(size(val)[2]) $(length(cols))") @@ -42,7 +45,12 @@ get_column_names(x::ResultsByTime) = x.column_names get_num_rows(::ResultsByTime{DenseAxisArray{Float64, 2}}, data) = length(axes(data)[2]) get_num_rows(::ResultsByTime{Matrix{Float64}}, data) = size(data)[1] -function _add_timestamps!(df::DataFrames.DataFrame, results::ResultsByTime, timestamp, data) +function _add_timestamps!( + df::DataFrames.DataFrame, + results::ResultsByTime, + timestamp::Dates.DateTime, + data, +) time_col = range(timestamp; length = get_num_rows(results, data), step = results.resolution) DataFrames.insertcols!(df, 1, :DateTime => time_col) diff --git a/src/operation/problem_results.jl b/src/operation/problem_results.jl index 44e07336d1..2f7ef03588 100644 --- a/src/operation/problem_results.jl +++ b/src/operation/problem_results.jl @@ -301,9 +301,9 @@ end function _read_results( result_values::Dict{<:OptimizationContainerKey, DataFrames.DataFrame}, container_keys, - timestamps, + timestamps::Vector{Dates.DateTime}, time_ids, - base_power::Number, + base_power::Float64, ) existing_keys = keys(result_values) container_keys = container_keys === nothing ? existing_keys : container_keys diff --git a/src/simulation/decision_model_simulation_results.jl b/src/simulation/decision_model_simulation_results.jl index 0864774575..fa6ceaf3e9 100644 --- a/src/simulation/decision_model_simulation_results.jl +++ b/src/simulation/decision_model_simulation_results.jl @@ -222,7 +222,7 @@ function _read_results( ::Type{T}, res::SimulationProblemResults{DecisionModelSimulationResults}, result_keys, - timestamps, + timestamps::Vector{Dates.DateTime}, store::Union{Nothing, <:SimulationStore}, ) where {T <: Union{Matrix{Float64}, DenseAxisArray{Float64, 2}}} isempty(result_keys) && return Dict{OptimizationContainerKey, ResultsByTime{T}}() @@ -458,10 +458,10 @@ function load_results!( initial_time = initial_time === nothing ? first(get_timestamps(res)) : initial_time res.results_timestamps = _process_timestamps(res, initial_time, count) dual_keys = [_deserialize_key(ConstraintKey, res, x...) for x in duals] - parameter_keys = [_deserialize_key(ParameterKey, res, x...) for x in parameters] - variable_keys = [_deserialize_key(VariableKey, res, x...) for x in variables] - aux_variable_keys = [_deserialize_key(AuxVarKey, res, x...) for x in aux_variables] - expression_keys = [_deserialize_key(ExpressionKey, res, x...) for x in expressions] + parameter_keys = ParameterKey[_deserialize_key(ParameterKey, res, x...) for x in parameters] + variable_keys = VariableKey[_deserialize_key(VariableKey, res, x...) for x in variables] + aux_variable_keys = AuxVarKey[_deserialize_key(AuxVarKey, res, x...) for x in aux_variables] + expression_keys = ExpressionKey[_deserialize_key(ExpressionKey, res, x...) for x in expressions] function merge_results(store) merge!( get_cached_variables(res), diff --git a/src/simulation/hdf_simulation_store.jl b/src/simulation/hdf_simulation_store.jl index 508f7e6b1a..e173d1636c 100644 --- a/src/simulation/hdf_simulation_store.jl +++ b/src/simulation/hdf_simulation_store.jl @@ -345,7 +345,7 @@ function read_result( if (ndims(data) < 2 || size(data)[1] == 1) && size(data)[2] != size(columns)[1] data = reshape(data, length(data), 1) end - return DataFrames.DataFrame(data, collect(columns); copycols = false) + return DataFrames.DataFrame(data, columns; copycols = false) end function read_result( @@ -519,8 +519,8 @@ function write_result!( key::OptimizationContainerKey, index::DecisionModelIndexType, ::Dates.DateTime, - data::DenseAxisArray{Float64, N, K}, -) where {N, K <: NTuple{N, Any}} + data::DenseAxisArray{Float64, N, <: NTuple{N, Any}}, +) where N output_cache = get_output_cache(store.cache, model_name, key) cur_size = get_size(store.cache) add_result!(output_cache, index, to_matrix(data), is_full(store.cache, cur_size)) From 87c3bfb0696c17046333c543887a139ae9acd17c Mon Sep 17 00:00:00 2001 From: Daniel Thom Date: Tue, 8 Aug 2023 11:41:06 -0600 Subject: [PATCH 245/370] Remove unused function --- src/utils/dataframes_utils.jl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/utils/dataframes_utils.jl b/src/utils/dataframes_utils.jl index 3dfadcadd3..4f78172b67 100644 --- a/src/utils/dataframes_utils.jl +++ b/src/utils/dataframes_utils.jl @@ -15,10 +15,6 @@ function to_dataframe(array::SparseAxisArray, key::OptimizationContainerKey) return DataFrames.DataFrame(to_matrix(array), get_column_names(key, array)) end -function to_dataframe(array::Matrix{Float64}, key::OptimizationContainerKey) - return DataFrames.DataFrame(array, get_column_names(key, array)) -end - function to_matrix(df::DataFrames.DataFrame) return Matrix{Float64}(df) end From 612e1d4abf23813c392f9d955daa062a2e540cbb Mon Sep 17 00:00:00 2001 From: Daniel Thom Date: Tue, 8 Aug 2023 11:57:39 -0600 Subject: [PATCH 246/370] Fix formatting --- src/simulation/decision_model_simulation_results.jl | 9 ++++++--- src/simulation/hdf_simulation_store.jl | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/simulation/decision_model_simulation_results.jl b/src/simulation/decision_model_simulation_results.jl index fa6ceaf3e9..f8bc532276 100644 --- a/src/simulation/decision_model_simulation_results.jl +++ b/src/simulation/decision_model_simulation_results.jl @@ -458,10 +458,13 @@ function load_results!( initial_time = initial_time === nothing ? first(get_timestamps(res)) : initial_time res.results_timestamps = _process_timestamps(res, initial_time, count) dual_keys = [_deserialize_key(ConstraintKey, res, x...) for x in duals] - parameter_keys = ParameterKey[_deserialize_key(ParameterKey, res, x...) for x in parameters] + parameter_keys = + ParameterKey[_deserialize_key(ParameterKey, res, x...) for x in parameters] variable_keys = VariableKey[_deserialize_key(VariableKey, res, x...) for x in variables] - aux_variable_keys = AuxVarKey[_deserialize_key(AuxVarKey, res, x...) for x in aux_variables] - expression_keys = ExpressionKey[_deserialize_key(ExpressionKey, res, x...) for x in expressions] + aux_variable_keys = + AuxVarKey[_deserialize_key(AuxVarKey, res, x...) for x in aux_variables] + expression_keys = + ExpressionKey[_deserialize_key(ExpressionKey, res, x...) for x in expressions] function merge_results(store) merge!( get_cached_variables(res), diff --git a/src/simulation/hdf_simulation_store.jl b/src/simulation/hdf_simulation_store.jl index e173d1636c..223407bea0 100644 --- a/src/simulation/hdf_simulation_store.jl +++ b/src/simulation/hdf_simulation_store.jl @@ -519,8 +519,8 @@ function write_result!( key::OptimizationContainerKey, index::DecisionModelIndexType, ::Dates.DateTime, - data::DenseAxisArray{Float64, N, <: NTuple{N, Any}}, -) where N + data::DenseAxisArray{Float64, N, <:NTuple{N, Any}}, +) where {N} output_cache = get_output_cache(store.cache, model_name, key) cur_size = get_size(store.cache) add_result!(output_cache, index, to_matrix(data), is_full(store.cache, cur_size)) From 4ae2f67ab47a1dcb251b90cb2c6269ef4970159c Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 9 Aug 2023 11:04:32 -0600 Subject: [PATCH 247/370] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index 1244af2cb0..b5c54293ec 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "PowerSimulations" uuid = "e690365d-45e2-57bb-ac84-44ba829e73c4" authors = ["Jose Daniel Lara", "Clayton Barrows", "Daniel Thom", "Dheepak Krishnamurthy", "Sourabh Dalvi"] -version = "0.21.1" +version = "0.21.2" [deps] CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" From 796affe1398c4f7a86f46804f80b2f85454b3023 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 9 Aug 2023 11:10:59 -0600 Subject: [PATCH 248/370] formatter --- src/core/parameters.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index 582539f25a..8b2ee49eb9 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -334,4 +334,4 @@ convert_result_to_natural_units(::Type{UpperBoundValueParameter}) = true convert_result_to_natural_units(::Type{LowerBoundValueParameter}) = true # TODO: Check if EnergyLimitParameter and EnergyTargetParameter should be removed convert_result_to_natural_units(::Type{EnergyLimitParameter}) = true -convert_result_to_natural_units(::Type{EnergyTargetParameter}) = true \ No newline at end of file +convert_result_to_natural_units(::Type{EnergyTargetParameter}) = true From 30581fa31a988149b19fb185662d06077d62af29 Mon Sep 17 00:00:00 2001 From: Barrows Date: Wed, 19 Jul 2023 13:05:53 -0400 Subject: [PATCH 249/370] adding missing stuff --- docs/Project.toml | 1 + src/core/parameters.jl | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/docs/Project.toml b/docs/Project.toml index 93b8458786..db78f98971 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -6,6 +6,7 @@ DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" DocumenterTools = "35a29f4d-8980-5a13-9543-d66fff28ecb8" GLPK = "60bf3e95-4087-53dc-ae20-288a0d20c6a6" +HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b" InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1" Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" PowerSimulations = "e690365d-45e2-57bb-ac84-44ba829e73c4" diff --git a/src/core/parameters.jl b/src/core/parameters.jl index 2e7975a430..58aa0322a6 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -303,13 +303,40 @@ struct OutflowTimeSeriesParameter <: TimeSeriesParameter end abstract type VariableValueParameter <: RightHandSideParameter end +""" +Parameter to define variable upper bound +""" struct UpperBoundValueParameter <: VariableValueParameter end + +""" +Parameter to define variable lower bound +""" struct LowerBoundValueParameter <: VariableValueParameter end + +""" +Parameter to define unit commitment status +""" struct OnStatusParameter <: VariableValueParameter end + +""" +Parameter to define energy limit +""" struct EnergyLimitParameter <: VariableValueParameter end + +""" +Parameter to define fixed output values +""" struct FixValueParameter <: VariableValueParameter end + + +""" +Parameter to define energy storage target +""" struct EnergyTargetParameter <: VariableValueParameter end +""" +Parameter to define cost function coefficient +""" struct CostFunctionParameter <: ObjectiveFunctionParameter end abstract type AuxVariableValueParameter <: RightHandSideParameter end From c7a2a7276e74ccca27e13871562cf43bbff11d51 Mon Sep 17 00:00:00 2001 From: Barrows Date: Wed, 19 Jul 2023 13:06:04 -0400 Subject: [PATCH 250/370] fixing hydro uc form --- docs/src/formulation_library/HydroGen.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md index efe13982b3..29704805f8 100644 --- a/docs/src/formulation_library/HydroGen.md +++ b/docs/src/formulation_library/HydroGen.md @@ -125,7 +125,7 @@ Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance ```math \begin{aligned} -& Pg_t \le Pg^\text{max}\\ +& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ & Pg_t - u_t Pg^\text{max} \le 0 \\ & Pg_t - u_t Pg^\text{min} \ge 0 \\ & Qg_t - u_t Qg^\text{max} \le 0 \\ From 0f05c33186217f2ceeddb554711b02d9a7c27b8a Mon Sep 17 00:00:00 2001 From: Clayton Barrows Date: Wed, 19 Jul 2023 13:39:49 -0400 Subject: [PATCH 251/370] Update src/core/parameters.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/core/parameters.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index 58aa0322a6..d20f0b40e4 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -328,7 +328,6 @@ Parameter to define fixed output values """ struct FixValueParameter <: VariableValueParameter end - """ Parameter to define energy storage target """ From bb44fcb203556b9e72aafaac4d28ef6efeea87d6 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 10 Jul 2023 17:27:17 -0600 Subject: [PATCH 252/370] create new model types --- docs/src/get_test_data.jl | 2 +- src/PowerSimulations.jl | 7 ++- src/core/optimization_container.jl | 6 ++- src/operation/decision_model.jl | 54 +++++++++++++++++--- src/operation/emulation_model.jl | 52 +++++++++++++++++-- src/operation/operation_model_interface.jl | 14 ++--- src/operation/operation_problem_templates.jl | 6 +-- src/operation/problem_template.jl | 12 +++++ test/test_utils/mock_operation_models.jl | 6 +-- 9 files changed, 126 insertions(+), 33 deletions(-) diff --git a/docs/src/get_test_data.jl b/docs/src/get_test_data.jl index 79e9e0acf3..2c99e65808 100644 --- a/docs/src/get_test_data.jl +++ b/docs/src/get_test_data.jl @@ -9,7 +9,7 @@ const PSY = PowerSystems include("../../../test/test_utils/get_test_data.jl") -abstract type TestOpProblem <: PSI.DecisionProblem end +abstract type TestOpProblem <: PSI.DefaultDecisionProblem end system = build_c_sys5_re(; add_reserves = true) solver = optimizer_with_attributes(Cbc.Optimizer) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 2fc2a5b2b6..11af3279a2 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -369,6 +369,7 @@ import Distributed # Base Imports import Base.getindex +import Base.isempty import Base.length import Base.first import InteractiveUtils: methodswith @@ -454,13 +455,11 @@ include("core/dataset.jl") include("core/dataset_container.jl") include("core/results_by_time.jl") +# Order Required +include("operation/problem_template.jl") include("core/optimization_container.jl") include("core/store_common.jl") - -# Order Required include("initial_conditions/initial_condition_chronologies.jl") - -include("operation/problem_template.jl") include("operation/operation_model_interface.jl") include("operation/model_store_params.jl") include("operation/abstract_model_store.jl") diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index 0e03fc33fa..3cdff305be 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -475,7 +475,11 @@ function initialize_system_expressions!( return end -function build_impl!(container::OptimizationContainer, template, sys::PSY.System) +function build_impl!( + container::OptimizationContainer, + template::ProblemTemplate, + sys::PSY.System, +) transmission = get_network_formulation(template) transmission_model = get_network_model(template) initialize_system_expressions!(container, transmission, transmission_model.subnetworks) diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index 623aab96db..be7e112603 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -1,7 +1,13 @@ """ -Default PowerSimulations Operation Problem Type +Abstract type for models than employ PowerSimulations methods. For custom decision problems + use DecisionProblem as the super type. """ -struct GenericOpProblem <: DecisionProblem end +abstract type DefaultDecisionProblem <: DecisionProblem end + +""" +Generic PowerSimulations Operation Problem Type for unspecified models +""" +struct GenericOpProblem <: DefaultDecisionProblem end """ DecisionModel{M}( @@ -10,7 +16,7 @@ struct GenericOpProblem <: DecisionProblem end jump_model::Union{Nothing, JuMP.Model}=nothing; kwargs...) where {M<:DecisionProblem} -This builds the optimization problem of type M with the specific system and template. +Builds the optimization problem of type M with the specific system and template. # Arguments @@ -136,7 +142,7 @@ function DecisionModel{M}( end """ -This builds the optimization problem of type M with the specific system and template +Builds the optimization problem of type M with the specific system and template # Arguments @@ -171,6 +177,30 @@ function DecisionModel( return DecisionModel{GenericOpProblem}(template, sys, jump_model; kwargs...) end +""" +Builds an empty decision model. This constructor is used for the implementation of custom +decision models that do not require a template. + +# Arguments + + - `::Type{M} where M<:DecisionProblem`: The abstract operation model type + - `sys::PSY.System`: 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 = DecisionModel(system, optimizer) +``` +""" +function DecisionModel{M}( + sys::PSY.System, + jump_model::Union{Nothing, JuMP.Model} = nothing; + kwargs..., +) where {M <: DecisionProblem} + return DecisionModel{M}(ProblemTemplate(), sys, jump_model; kwargs...) +end + """ Construct an DecisionProblem from a serialized file. @@ -200,6 +230,9 @@ function DecisionModel( ) end +get_problem_type(::DecisionModel{M}) where {M <: DecisionProblem} = M +validate_template(::DecisionModel{<:DecisionProblem}) = nothing + # Probably could be more efficient by storing the info in the internal function get_current_time(model::DecisionModel) execution_count = get_internal(model).execution_count @@ -228,9 +261,9 @@ function init_model_store_params!(model::DecisionModel) return end -function build_pre_step!(model::DecisionModel) +function build_pre_step!(model::DecisionModel{<:DefaultDecisionProblem}) TimerOutputs.@timeit BUILD_PROBLEMS_TIMER "Build pre-step" begin - if !is_empty(model) + if !isempty(model) @info "OptimizationProblem status not BuildStatus.EMPTY. Resetting" reset!(model) end @@ -254,6 +287,15 @@ function build_pre_step!(model::DecisionModel) return end +function build_impl!(model::DecisionModel{<:DefaultDecisionProblem}) + validate_template(model) + build_pre_step!(model) + build_model!(model) + serialize_metadata!(get_optimization_container(model), get_output_dir(model)) + log_values(get_settings(model)) + return +end + get_horizon(model::DecisionModel) = get_horizon(get_settings(model)) """ diff --git a/src/operation/emulation_model.jl b/src/operation/emulation_model.jl index 724134c344..f3e60c9d48 100644 --- a/src/operation/emulation_model.jl +++ b/src/operation/emulation_model.jl @@ -1,7 +1,13 @@ """ -Default PowerSimulations Emulation Problem Type +Abstract type for models than employ PowerSimulations methods. For custom emulation problems + use EmulationProblem as the super type. """ -struct GenericEmulationProblem <: EmulationProblem end +abstract type DefaultEmulationProblem <: EmulationProblem end + +""" +Default PowerSimulations Emulation Problem Type for unspecified problems +""" +struct GenericEmulationProblem <: DefaultEmulationProblem end """ EmulationModel{M}( @@ -10,7 +16,7 @@ struct GenericEmulationProblem <: EmulationProblem end jump_model::Union{Nothing, JuMP.Model}=nothing; kwargs...) where {M<:EmulationProblem} -This builds the optimization problem of type M with the specific system and template. +Builds the optimization problem of type M with the specific system and template. # Arguments @@ -126,7 +132,7 @@ function EmulationModel{M}( end """ -This builds the optimization problem of type M with the specific system and template +Builds the optimization problem of type M with the specific system and template # Arguments @@ -162,6 +168,30 @@ function EmulationModel( 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::PSY.System`: 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::PSY.System, + jump_model::Union{Nothing, JuMP.Model} = nothing; + kwargs..., +) where {M <: EmulationProblem} + return EmulationModel{M}(template, sys, jump_model; kwargs...) +end + """ Construct an EmulationProblem from a serialized file. @@ -192,6 +222,9 @@ function EmulationModel( ) end +get_problem_type(::EmulationModel{M}) where {M <: EmulationProblem} = M +validate_template(::EmulationModel{<:EmulationProblem}) = nothing + function get_current_time(model::EmulationModel) execution_count = get_internal(model).execution_count initial_time = get_initial_time(model) @@ -219,7 +252,7 @@ end function build_pre_step!(model::EmulationModel) TimerOutputs.@timeit BUILD_PROBLEMS_TIMER "Build pre-step" begin - if !is_empty(model) + if !isempty(model) @info "EmulationProblem status not BuildStatus.EMPTY. Resetting" reset!(model) end @@ -243,6 +276,15 @@ function build_pre_step!(model::EmulationModel) return end +function build_impl!(model::EmulationModel{<:DefaultEmulationProblem}) + validate_template(model) + build_pre_step!(model) + build_model!(model) + serialize_metadata!(get_optimization_container(model), get_output_dir(model)) + log_values(get_settings(model)) + return +end + """ Implementation of build for any EmulationProblem """ diff --git a/src/operation/operation_model_interface.jl b/src/operation/operation_model_interface.jl index fb2b302e5b..bb925f4441 100644 --- a/src/operation/operation_model_interface.jl +++ b/src/operation/operation_model_interface.jl @@ -1,6 +1,6 @@ # Default implementations of getter/setter functions for OperationModel. is_built(model::OperationModel) = model.internal.status == BuildStatus.BUILT -is_empty(model::OperationModel) = model.internal.status == BuildStatus.EMPTY +isempty(model::OperationModel) = model.internal.status == BuildStatus.EMPTY warm_start_enabled(model::OperationModel) = get_warm_start(get_optimization_container(model).settings) built_for_recurrent_solves(model::OperationModel) = @@ -213,6 +213,9 @@ end function validate_template(model::OperationModel) template = get_template(model) + if isempty(template) + error("Template can't be empty for models $(get_problem_type(model))") + end modeled_types = get_component_types(template) system = get_system(model) system_component_types = PSY.get_existing_component_types(system) @@ -228,15 +231,6 @@ function validate_template(model::OperationModel) return end -function build_impl!(model::OperationModel) - validate_template(model) - build_pre_step!(model) - build_model!(model) - serialize_metadata!(get_optimization_container(model), get_output_dir(model)) - log_values(get_settings(model)) - return -end - function build_if_not_already_built!(model; kwargs...) status = get_status(model) if status == BuildStatus.EMPTY diff --git a/src/operation/operation_problem_templates.jl b/src/operation/operation_problem_templates.jl index 5a60c03c52..fb6a1f9206 100644 --- a/src/operation/operation_problem_templates.jl +++ b/src/operation/operation_problem_templates.jl @@ -1,7 +1,7 @@ -struct EconomicDispatchProblem <: DecisionProblem end -struct UnitCommitmentProblem <: DecisionProblem end -struct AGCReserveDeployment <: DecisionProblem end +struct EconomicDispatchProblem <: DefaultDecisionProblem end +struct UnitCommitmentProblem <: DefaultDecisionProblem end +struct AGCReserveDeployment <: DefaultDecisionProblem end function _default_devices_uc() return [ diff --git a/src/operation/problem_template.jl b/src/operation/problem_template.jl index 92e86e8fc5..eca8246cde 100644 --- a/src/operation/problem_template.jl +++ b/src/operation/problem_template.jl @@ -31,6 +31,18 @@ mutable struct ProblemTemplate end end +function Base.isempty(template::ProblemTemplate) + if !isempty(template.devices) + return false + elseif !isempty(template.branches) + return false + elseif !isempty(template.services) + return false + else + return true + end +end + ProblemTemplate(::Type{T}) where {T <: PM.AbstractPowerModel} = ProblemTemplate(NetworkModel(T)) ProblemTemplate() = ProblemTemplate(CopperPlatePowerModel) diff --git a/test/test_utils/mock_operation_models.jl b/test/test_utils/mock_operation_models.jl index 4f00ac010f..49b276d237 100644 --- a/test/test_utils/mock_operation_models.jl +++ b/test/test_utils/mock_operation_models.jl @@ -1,8 +1,8 @@ # NOTE: None of the models and function in this file are functional. All of these are used for testing purposes and do not represent valid examples either to develop custom # models. Please refer to the documentation. -struct MockOperationProblem <: PSI.DecisionProblem end -struct MockEmulationProblem <: PSI.EmulationProblem end +struct MockOperationProblem <: PSI.DefaultDecisionProblem end +struct MockEmulationProblem <: PSI.DefaultEmulationProblem end function PSI.DecisionModel( ::Type{MockOperationProblem}, @@ -194,7 +194,7 @@ end function setup_ic_model_container!(model::DecisionModel) # This function is only for testing purposes. - if !PSI.is_empty(model) + if !PSI.isempty(model) PSI.reset!(model) end From 58d0cce38fa9ad9c96cab6324cb4ed64730cd9a7 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 10 Jul 2023 20:47:28 -0600 Subject: [PATCH 253/370] additional updates to build custom models --- src/operation/decision_model.jl | 47 ++++++++----- src/operation/decision_model_store.jl | 4 ++ src/operation/emulation_model.jl | 29 +++++--- src/operation/operation_model_interface.jl | 79 ++++++++++++---------- 4 files changed, 95 insertions(+), 64 deletions(-) diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index be7e112603..9dbfc499a1 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -71,12 +71,6 @@ mutable struct DecisionModel{M <: DecisionProblem} <: OperationModel elseif name isa String name = Symbol(name) end - _, _, forecast_count = PSY.get_time_series_counts(sys) - if forecast_count < 1 - error( - "The system does not contain forecast data. A DecisionModel can't be built.", - ) - end internal = ModelInternal( OptimizationContainer(sys, settings, jump_model, PSY.Deterministic), ) @@ -201,6 +195,16 @@ function DecisionModel{M}( return DecisionModel{M}(ProblemTemplate(), sys, jump_model; kwargs...) end +function DecisionModel{M}( + sys::PSY.System, + jump_model::Union{Nothing, JuMP.Model} = nothing; + kwargs..., +) where {M <: DefaultDecisionProblem} + IS.ArgumentError( + "DefaultDecisionProblem subtypes require a template. Use DecisionModel subtyping instead.", + ) +end + """ Construct an DecisionProblem from a serialized file. @@ -232,6 +236,7 @@ end get_problem_type(::DecisionModel{M}) where {M <: DecisionProblem} = M validate_template(::DecisionModel{<:DecisionProblem}) = nothing +validate_time_series(::DecisionModel{<:DecisionProblem}) = nothing # Probably could be more efficient by storing the info in the internal function get_current_time(model::DecisionModel) @@ -261,35 +266,45 @@ function init_model_store_params!(model::DecisionModel) return end -function build_pre_step!(model::DecisionModel{<:DefaultDecisionProblem}) +function validate_time_series(model::DecisionModel{<:DefaultDecisionProblem}) + sys = get_system(model) + _, _, forecast_count = PSY.get_time_series_counts(sys) + if forecast_count < 1 + error( + "The system does not contain forecast data. A DecisionModel can't be built.", + ) + end + return +end + +function build_pre_step!(model::DecisionModel{<:DecisionProblem}) TimerOutputs.@timeit BUILD_PROBLEMS_TIMER "Build pre-step" begin + validate_template(model) + validate_time_series(model) if !isempty(model) @info "OptimizationProblem status not BuildStatus.EMPTY. Resetting" reset!(model) end # Initial time are set here because the information is specified in the # Simulation Sequence object and not at the problem creation. - @info "Initializing Optimization Container For a DecisionModel" init_optimization_container!( get_optimization_container(model), get_network_formulation(get_template(model)), get_system(model), ) - @info "Instantiating Network Model" - instantiate_network_model(model) @info "Initializing ModelStoreParams" init_model_store_params!(model) - - handle_initial_conditions!(model) set_status!(model, BuildStatus.IN_PROGRESS) end return end -function build_impl!(model::DecisionModel{<:DefaultDecisionProblem}) - validate_template(model) +function build_impl!(model::DecisionModel{<:DecisionProblem}) build_pre_step!(model) + @info "Instantiating Network Model" + instantiate_network_model(model) + handle_initial_conditions!(model) build_model!(model) serialize_metadata!(get_optimization_container(model), get_output_dir(model)) log_values(get_settings(model)) @@ -353,12 +368,12 @@ end Default implementation of build method for Operational Problems for models conforming with DecisionProblem specification. Overload this function to implement a custom build method """ -function build_model!(model::DecisionModel) +function build_model!(model::DecisionModel{<:DefaultDecisionProblem}) build_impl!(get_optimization_container(model), get_template(model), get_system(model)) return end -function reset!(model::DecisionModel) +function reset!(model::DecisionModel{<:DefaultDecisionProblem}) was_built_for_recurrent_solves = built_for_recurrent_solves(model) if was_built_for_recurrent_solves set_execution_count!(model, 0) diff --git a/src/operation/decision_model_store.jl b/src/operation/decision_model_store.jl index a6323dfd2d..102460b2ca 100644 --- a/src/operation/decision_model_store.jl +++ b/src/operation/decision_model_store.jl @@ -31,6 +31,9 @@ function initialize_storage!( params::ModelStoreParams, ) num_of_executions = get_num_executions(params) + if length(get_time_steps(container)) < 1 + error("The time step count in the optimization container is not defined") + end time_steps_count = get_time_steps(container)[end] initial_time = get_initial_time(container) model_interval = get_interval(params) @@ -53,6 +56,7 @@ function initialize_storage!( results_container[key] = data end end + return end function write_result!( diff --git a/src/operation/emulation_model.jl b/src/operation/emulation_model.jl index f3e60c9d48..b71350744b 100644 --- a/src/operation/emulation_model.jl +++ b/src/operation/emulation_model.jl @@ -70,12 +70,6 @@ mutable struct EmulationModel{M <: EmulationProblem} <: OperationModel elseif name isa String name = Symbol(name) end - _, ts_count, _ = PSY.get_time_series_counts(sys) - if ts_count < 1 - error( - "The system does not contain Static TimeSeries data. An Emulation model can't be formulated.", - ) - end finalize_template!(template, sys) internal = ModelInternal( OptimizationContainer(sys, settings, jump_model, PSY.SingleTimeSeries), @@ -224,6 +218,7 @@ end get_problem_type(::EmulationModel{M}) where {M <: EmulationProblem} = M validate_template(::EmulationModel{<:EmulationProblem}) = nothing +validate_time_series(::EmulationModel{<:EmulationProblem}) = nothing function get_current_time(model::EmulationModel) execution_count = get_internal(model).execution_count @@ -250,8 +245,21 @@ function init_model_store_params!(model::EmulationModel) return end +function validate_time_series(model::EmulationModel{<:DefaultEmulationProblem}) + sys = get_system(model) + _, ts_count, _ = PSY.get_time_series_counts(sys) + if ts_count < 1 + error( + "The system does not contain Static TimeSeries data. An Emulation model can't be formulated.", + ) + end + return +end + function build_pre_step!(model::EmulationModel) TimerOutputs.@timeit BUILD_PROBLEMS_TIMER "Build pre-step" begin + validate_template(model) + validate_time_series(model) if !isempty(model) @info "EmulationProblem status not BuildStatus.EMPTY. Resetting" reset!(model) @@ -265,20 +273,19 @@ function build_pre_step!(model::EmulationModel) get_network_formulation(get_template(model)), get_system(model), ) - @info "Instantiating Network Model" - instantiate_network_model(model) @info "Initializing ModelStoreParams" init_model_store_params!(model) - handle_initial_conditions!(model) set_status!(model, BuildStatus.IN_PROGRESS) end return end -function build_impl!(model::EmulationModel{<:DefaultEmulationProblem}) - validate_template(model) +function build_impl!(model::EmulationModel{<:EmulationProblem}) build_pre_step!(model) + @info "Instantiating Network Model" + instantiate_network_model(model) + handle_initial_conditions!(model) build_model!(model) serialize_metadata!(get_optimization_container(model), get_output_dir(model)) log_values(get_settings(model)) diff --git a/src/operation/operation_model_interface.jl b/src/operation/operation_model_interface.jl index bb925f4441..53aae2f0fb 100644 --- a/src/operation/operation_model_interface.jl +++ b/src/operation/operation_model_interface.jl @@ -144,48 +144,53 @@ function write_initial_conditions_data!(model::OperationModel) end function handle_initial_conditions!(model::OperationModel) - settings = get_settings(model) - initialize_model = get_initialize_model(settings) - deserialize_initial_conditions = get_deserialize_initial_conditions(settings) - serialized_initial_conditions_file = get_initial_conditions_file(model) - custom_init_file = get_initialization_file(settings) - - if !initialize_model && deserialize_initial_conditions - throw( - IS.ConflictingInputsError( - "!initialize_model && deserialize_initial_conditions", - ), - ) - elseif !initialize_model && !isempty(custom_init_file) - throw(IS.ConflictingInputsError("!initialize_model && initialization_file")) - end - - if !initialize_model - @info "Skip build of initial conditions" - return - end + TimerOutputs.@timeit BUILD_PROBLEMS_TIMER "Model Initialization" begin + if isempty(get_template(model)) + return + end + settings = get_settings(model) + initialize_model = get_initialize_model(settings) + deserialize_initial_conditions = get_deserialize_initial_conditions(settings) + serialized_initial_conditions_file = get_initial_conditions_file(model) + custom_init_file = get_initialization_file(settings) + + if !initialize_model && deserialize_initial_conditions + throw( + IS.ConflictingInputsError( + "!initialize_model && deserialize_initial_conditions", + ), + ) + elseif !initialize_model && !isempty(custom_init_file) + throw(IS.ConflictingInputsError("!initialize_model && initialization_file")) + end - if !isempty(custom_init_file) - if !isfile(custom_init_file) - error("initialization_file = $custom_init_file does not exist") + if !initialize_model + @info "Skip build of initial conditions" + return end - if abspath(custom_init_file) != abspath(serialized_initial_conditions_file) - cp(custom_init_file, serialized_initial_conditions_file; force = true) + + if !isempty(custom_init_file) + if !isfile(custom_init_file) + error("initialization_file = $custom_init_file does not exist") + end + if abspath(custom_init_file) != abspath(serialized_initial_conditions_file) + cp(custom_init_file, serialized_initial_conditions_file; force = true) + end end - end - if deserialize_initial_conditions && isfile(serialized_initial_conditions_file) - set_initial_conditions_data!( - model.internal.container, - Serialization.deserialize(serialized_initial_conditions_file), - ) - @info "Deserialized initial_conditions_data" - else - @info "Make Initial Conditions Model" - build_initial_conditions!(model) - initialize!(model) + if deserialize_initial_conditions && isfile(serialized_initial_conditions_file) + set_initial_conditions_data!( + model.internal.container, + Serialization.deserialize(serialized_initial_conditions_file), + ) + @info "Deserialized initial_conditions_data" + else + @info "Make Initial Conditions Model" + build_initial_conditions!(model) + initialize!(model) + end + model.internal.ic_model_container = nothing end - model.internal.ic_model_container = nothing return end From b82df032b03eedfbed8b92f8eac636b16d9bee1c Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 10:12:55 -0600 Subject: [PATCH 254/370] improvements to objective function --- src/core/optimization_container.jl | 34 ++++++++++++++++-------- src/operation/decision_model.jl | 2 +- src/operation/emulation_model.jl | 2 +- test/test_utils/mock_operation_models.jl | 2 +- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index 3cdff305be..30fcde7078 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -54,15 +54,30 @@ mutable struct ObjectiveFunction invariant_terms::JuMP.AbstractJuMPScalar variant_terms::GAE synchronized::Bool + sense::MOI.OptimizationSense + function ObjectiveFunction(invariant_terms::JuMP.AbstractJuMPScalar, + variant_terms::GAE, + synchronized::Bool, + sense::MOI.OptimizationSense = MOI.MIN_SENSE) + new(invariant_terms, variant_terms, synchronized, sense) + end end get_invariant_terms(v::ObjectiveFunction) = v.invariant_terms get_variant_terms(v::ObjectiveFunction) = v.variant_terms -get_objective_function(v::ObjectiveFunction) = v.variant_terms + v.invariant_terms +function get_objective_expression(v::ObjectiveFunction) + if iszero(v.variant_terms) + return v.invariant_terms + else + return JuMP.add_to_expression!(v.variant_terms, v.invariant_terms) + end +end +get_sense(v::ObjectiveFunction) = v.sense is_synchronized(v::ObjectiveFunction) = v.synchronized set_synchronized_status(v::ObjectiveFunction, value) = v.synchronized = value reset_variant_terms(v::ObjectiveFunction) = v.variant_terms = zero(JuMP.AffExpr) has_variant_terms(v::ObjectiveFunction) = !iszero(v.variant_terms) +set_sense!(v::ObjectiveFunction, sense::MOI.OptimizationSense) = v.sense = sense function ObjectiveFunction() return ObjectiveFunction( @@ -150,7 +165,7 @@ get_base_power(container::OptimizationContainer) = container.base_power get_constraints(container::OptimizationContainer) = container.constraints function cost_function_unsynch(container::OptimizationContainer) - obj_func = PSI.get_objective_function(container) + obj_func = PSI.get_objective_expression(container) if has_variant_terms(obj_func) && PSI.is_synchronized(container) PSI.set_synchronized_status(obj_func, false) PSI.reset_variant_terms(obj_func) @@ -183,9 +198,10 @@ get_variables(container::OptimizationContainer) = container.variables set_initial_conditions_data!(container::OptimizationContainer, data) = container.initial_conditions_data = data -get_objective_function(container::OptimizationContainer) = container.objective_function +get_objective_expression(container::OptimizationContainer) = container.objective_function is_synchronized(container::OptimizationContainer) = container.objective_function.synchronized +set_time_steps!(container::OptimizationContainer, time_steps::UnitRange{Int64}) = container.time_steps = time_steps function has_container_key( container::OptimizationContainer, @@ -588,11 +604,7 @@ function build_impl!( TimerOutputs.@timeit BUILD_PROBLEMS_TIMER "Objective" begin @debug "Building Objective" _group = LOG_GROUP_OPTIMIZATION_CONTAINER - JuMP.@objective( - container.JuMPmodel, - MOI.MIN_SENSE, - get_objective_function(container.objective_function) - ) + update_objective_function!(container) end @debug "Total operation count $(container.JuMPmodel.operator_counter)" _group = LOG_GROUP_OPTIMIZATION_CONTAINER @@ -604,9 +616,9 @@ end function update_objective_function!(container::OptimizationContainer) JuMP.@objective( - container.JuMPmodel, - MOI.MIN_SENSE, - get_objective_function(container.objective_function) + get_jump_model(container), + get_sense(container.objective_function), + get_objective_expression(container.objective_function) ) return end diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index 9dbfc499a1..20403486a2 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -528,7 +528,7 @@ function update_parameters!( end if !is_synchronized(model) update_objective_function!(get_optimization_container(model)) - obj_func = get_objective_function(get_optimization_container(model)) + obj_func = get_objective_expression(get_optimization_container(model)) set_synchronized_status(obj_func, true) end return diff --git a/src/operation/emulation_model.jl b/src/operation/emulation_model.jl index b71350744b..2186f8de4d 100644 --- a/src/operation/emulation_model.jl +++ b/src/operation/emulation_model.jl @@ -375,7 +375,7 @@ function update_parameters!(model::EmulationModel, data::DatasetContainer{InMemo end if !is_synchronized(model) update_objective_function!(get_optimization_container(model)) - obj_func = get_objective_function(get_optimization_container(model)) + obj_func = get_objective_expression(get_optimization_container(model)) set_synchronized_status(obj_func, true) end return diff --git a/test/test_utils/mock_operation_models.jl b/test/test_utils/mock_operation_models.jl index 49b276d237..f1166c01cb 100644 --- a/test/test_utils/mock_operation_models.jl +++ b/test/test_utils/mock_operation_models.jl @@ -139,7 +139,7 @@ function mock_construct_device!( JuMP.@objective( PSI.get_jump_model(problem), MOI.MIN_SENSE, - PSI.get_objective_function( + PSI.get_objective_expression( PSI.get_optimization_container(problem).objective_function, ) ) From 591f2f702b6ad56086421bbe7490e040c8ec8ea8 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 12:26:30 -0600 Subject: [PATCH 255/370] improve docs pages --- .../adding_new_problem_model.md | 6 -- .../structure_of_operation_problem.md | 10 +++ docs/src/modeler_guide/definitions.md | 6 +- .../adding_new_device_formulation.md | 0 .../src/tutorials/adding_new_problem_model.md | 85 +++++++++++++++++++ .../tutorials/basics_of_developing_models.md | 3 + 6 files changed, 101 insertions(+), 9 deletions(-) delete mode 100644 docs/src/model_developer_guide/adding_new_problem_model.md create mode 100644 docs/src/model_developer_guide/structure_of_operation_problem.md rename docs/src/{model_developer_guide => tutorials}/adding_new_device_formulation.md (100%) create mode 100644 docs/src/tutorials/adding_new_problem_model.md create mode 100644 docs/src/tutorials/basics_of_developing_models.md diff --git a/docs/src/model_developer_guide/adding_new_problem_model.md b/docs/src/model_developer_guide/adding_new_problem_model.md deleted file mode 100644 index 9083c2309c..0000000000 --- a/docs/src/model_developer_guide/adding_new_problem_model.md +++ /dev/null @@ -1,6 +0,0 @@ -# Adding an Operations Problem Model - -## Decision Problem - - -## Emulation Problem diff --git a/docs/src/model_developer_guide/structure_of_operation_problem.md b/docs/src/model_developer_guide/structure_of_operation_problem.md new file mode 100644 index 0000000000..b4d67b51d0 --- /dev/null +++ b/docs/src/model_developer_guide/structure_of_operation_problem.md @@ -0,0 +1,10 @@ +# Structure of an operations problem model + +In most cases operation problem models are optimization models. Although in `PowerSimulations.jl` it is +possible to define arbitrary problems that can reflect heuristic decision rules, this is not the common case. This page focuses on explaining the structure of operations problems that employ and optimization problem and solver. + +The first aspect to consider when thinking about developing a model compatible with `PowerSimulations.jl` is that although we support all of `JuMP.jl` objects, you need to employ [anonymous constraints and variables in JuMP](https://jump.dev/JuMP.jl/stable/manual/variables/#anonymous_variables) +and register the constraints, variables and other optimization objects into PowerSimulations.jl's optimization container. Otherwise the features to use your problem in the simulation like the coordination with other problems and post processing won't work. + +!!! info + The requirements for the simulation of Power Systems operations are more strict than solving an optimization problem once with just `JuMP.jl`. The requirements imposed by `PowerSimulations.jl` to integrate your models in a simulation are designed to help with other complex operations that go beyond `JuMP.jl` scope. diff --git a/docs/src/modeler_guide/definitions.md b/docs/src/modeler_guide/definitions.md index cc42de6e72..77a91065e0 100644 --- a/docs/src/modeler_guide/definitions.md +++ b/docs/src/modeler_guide/definitions.md @@ -10,12 +10,12 @@ ## H -* *Horizon*: The number of steps in the look-ahead of a decision problem. For instance, a Day-ahead problem usually has a 48 step horizon. +* *Horizon*: The number of steps in the look-ahead of a decision problem. For instance, a Day-Ahead problem usually has a 48 step horizon. Check the time [Time Series Data Section in PowerSystems.jl](https://nrel-sienna.github.io/PowerSystems.jl/stable/modeler_guide/time_series/) ## I -* *Interval*: +* *Interval*: The amount of time between updates to the decision problem. For instance, Day-Ahead problems usually have a 24-hour intervals and Real-Time problems have 5-minute intervals. Check the time [Time Series Data Section in PowerSystems.jl](https://nrel-sienna.github.io/PowerSystems.jl/stable/modeler_guide/time_series/) ## R -* *Resolution*: The amount of time between timesteps in a simulation. For instance 1-hour or 5-minutes. In Julia these are defined using the syntax `Hour(1)` and `Minute(5)` +* *Resolution*: The amount of time between timesteps in a simulation. For instance 1-hour or 5-minutes. In Julia these are defined using the syntax `Hour(1)` and `Minute(5)`. Check the time [Time Series Data Section in PowerSystems.jl](https://nrel-sienna.github.io/PowerSystems.jl/stable/modeler_guide/time_series/) diff --git a/docs/src/model_developer_guide/adding_new_device_formulation.md b/docs/src/tutorials/adding_new_device_formulation.md similarity index 100% rename from docs/src/model_developer_guide/adding_new_device_formulation.md rename to docs/src/tutorials/adding_new_device_formulation.md diff --git a/docs/src/tutorials/adding_new_problem_model.md b/docs/src/tutorials/adding_new_problem_model.md new file mode 100644 index 0000000000..0134dd58b4 --- /dev/null +++ b/docs/src/tutorials/adding_new_problem_model.md @@ -0,0 +1,85 @@ +# Adding an Operations Problem Model + +This tutorial will show how to create a custom decision problem model. These cases are the ones +where the user want to solve a fully specified problem. Some examples of custom decision models include: + +- Solving a custom Security Constrained Unit Commitment Problem +- Solving a market agent utility maximization Problem. See examples of this functionality in HybridSystemsSimulations.jl + +The tutorial follows the usual steps for operational model building. First, build the decision model in isolation and second integrate int a simulation. In most cases there will be more than one way of achieving +the same objective when it comes to implementing the model. This guide shows a general set of steps and requirements but it is by no means an exhaustive and detailed guide on developing custom decision models. + +!!! warning + All the code in this tutorial is considered "pseudo-code". If you copy-paste will likely not work out of the box. You need to develop the internals of the functions correctly for the examples below to work. + +## General Rules + +1. As a general rule you need to understand Julia's terminology such as multiple dispatch, parametried structs and method overloading among others. Developing custom models for an operational simulation is highly technical task and requires skilled development. This tuturial also requires good understanding of PowerSystems.jl data structures and features which are covered in the tutorials section of PowerSystems.jl documentation. +Finally, developing a custom model decision model that will employ an optimization model under the hood requires understanding JuMP.jl. + +2. Need to employ [anonymous constraints and variables in JuMP](https://jump.dev/JuMP.jl/stable/manual/variables/#anonymous_variables) +and register the constraints, variables and other optimization objects into PowerSimulations.jl's optimization container. Otherwise the +features to use your problem in the simulation like the coordination with other problems and post processing won't work. More on this in the section [How to develop your `build_model!` function](@ref) below. + +3. Overload the required methods for your custom decision models. In some cases it will be possible to re-use some of the other methods that exist in PowerSimulations to make life easier for variable addition and constraint creation but this is not required. + +## Decision Problem + +### Step 1: Define a Custom Decision Problem + +Define a decision problem struct as a subtype of `PowerSimulations.DecisionProblem`. This requirement will enable a lot of the underlying functionality that relies on multiple dispatch. DecisionProblems are used to parameterize the behavior of `DecisionModel` objects which are just containers +for the parameters, references and the optimization problem. + +It is possible to define a Custom Decision Problem that gives the user full control over the build, solve and execution process since it imposes less requirements on the developer. However, with less requirements there are also less check and validations performed inside of PowerSimulations which might lead to unexpected erros. + +```julia +struct MyCustomDecisionProblem <: PSI.DecisionProblem end +``` + +Alternatevely, it is possible to define a Custom Decision Problem subtyping from `DefaultDecisionProblem` which imposes more requirements and structure onto the developer but employs more checks and validations in the process. Be aware that this route will decrease the flexibility of what can be done inside the custom model. + +```julia +struct MyCustomDecisionProblem <: PSI.DefaultDecisionProblem end +``` + +Once the problem type is defined, initialize the decision model container with your custom decision problem passing the solver and some of the settings you need for the solution of the problem. For custom problems some of the settings need manual implementation by the developer. Settings availability is also dependent on wether you choose to subtype from `PSI.DecisionProblem` or `PSI.DefaultDecisionProblem` + +```julia +my_model = DecisionModel{MyCustomDecisionProblem}( + sys; + name = "MyModel", + optimizer = optimizer_with_attributes(HiGHS.Optimizer), + optimizer_solve_log_print = true, +) +``` + +#### Mandatory Method Overloads + +1. `build_model!`: This method build the `JuMP` optimization model. + +#### Optional Method Overloads + +These methods can be defined optionally for your problem. By default for problems subtyped from `DecisionProblem` these checks are not executed. If the problems are subtyped from `DefaultDecisionProblem` these checks are always conducted with PowerSimulations defaults and require compliance with those defaults to pass. In any case, these can be overloaded when necessary depending on the problem requirements. + +1. `validate_template` +2. `validate_time_series` +3. `reset!` +4. `solve_impl!` + +### How to develop your `build_model!` function + + + +```julia +function PSI.build_model!(model::PSI.DecisionModel{MyCustomDecisionProblem}) + container = PSI.get_optimization_container(model) + PSI.set_time_steps!(container, 1:24) # <- Mandatory + system = PSI.get_system(model) + + + + update_objective_function!(container) # <- Mandatory +end +``` + +## Emulation Problem diff --git a/docs/src/tutorials/basics_of_developing_models.md b/docs/src/tutorials/basics_of_developing_models.md new file mode 100644 index 0000000000..a027918d6a --- /dev/null +++ b/docs/src/tutorials/basics_of_developing_models.md @@ -0,0 +1,3 @@ +# Basics of Developing Operation Models + +Check the page [PowerSimulations Structure](@ref) for more background on PowerSimulations.jl From 783ce79297a9bd6ff43b19befb5c5ef15444219b Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 14:23:23 -0600 Subject: [PATCH 256/370] formatter --- src/core/optimization_container.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index 30fcde7078..eb0cb5b93c 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -201,7 +201,8 @@ set_initial_conditions_data!(container::OptimizationContainer, data) = get_objective_expression(container::OptimizationContainer) = container.objective_function is_synchronized(container::OptimizationContainer) = container.objective_function.synchronized -set_time_steps!(container::OptimizationContainer, time_steps::UnitRange{Int64}) = container.time_steps = time_steps +set_time_steps!(container::OptimizationContainer, time_steps::UnitRange{Int64}) = + container.time_steps = time_steps function has_container_key( container::OptimizationContainer, From 77c6acfbc81470879691d77b2cbe2a4e8b434158 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 15:51:34 -0600 Subject: [PATCH 257/370] remove more hybrid --- docs/src/api/PowerSimulations.md | 20 -------------------- src/PowerSimulations.jl | 7 ------- src/core/constraints.jl | 6 ------ src/core/variables.jl | 8 -------- 4 files changed, 41 deletions(-) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index 6440195532..923befca92 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -130,14 +130,6 @@ PowerAboveMinimumVariable ReservationVariable ``` -### Common for Hydro and Storage Variables - -```@docs -ActivePowerOutVariable -ActivePowerInVariable -EnergyVariable -``` - ### Branches and Network Variables ```@docs @@ -236,18 +228,6 @@ EqualityConstraint ``` -### Hydro and Storage Constraints - -```@docs -EnergyBalanceConstraint -EnergyBudgetConstraint -EnergyCapacityConstraint -EnergyCapacityDownConstraint -EnergyCapacityUpConstraint -EnergyTargetConstraint -RangeLimitConstraint -``` - ### Branches Constraints ```@docs diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 11af3279a2..3502ccae0d 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -212,7 +212,6 @@ export ReactivePowerVariable export ReservationVariable export ActivePowerReserveVariable export ServiceRequirementVariable -export WaterSpillageVariable export StartVariable export StopVariable export SteadyStateFrequencyDeviation @@ -254,12 +253,6 @@ export CommitmentConstraint export CopperPlateBalanceConstraint export DurationConstraint export EnergyBalanceConstraint -export EnergyBudgetConstraint -export EnergyCapacityConstraint -export EnergyCapacityDownConstraint -export EnergyCapacityUpConstraint -export EnergyLimitConstraint -export EnergyTargetConstraint export EqualityConstraint export FeedforwardSemiContinousConstraint export FeedforwardUpperBoundConstraint diff --git a/src/core/constraints.jl b/src/core/constraints.jl index 1771a0b784..f48ad59795 100644 --- a/src/core/constraints.jl +++ b/src/core/constraints.jl @@ -36,12 +36,6 @@ struct CommitmentConstraint <: ConstraintType end struct CopperPlateBalanceConstraint <: ConstraintType end struct DurationConstraint <: ConstraintType end struct EnergyBalanceConstraint <: ConstraintType end -struct EnergyBudgetConstraint <: ConstraintType end -struct EnergyCapacityConstraint <: ConstraintType end -struct EnergyCapacityDownConstraint <: ConstraintType end -struct EnergyCapacityUpConstraint <: ConstraintType end -struct EnergyLimitConstraint <: ConstraintType end # not being used -struct EnergyTargetConstraint <: ConstraintType end struct EqualityConstraint <: ConstraintType end struct FeedforwardSemiContinousConstraint <: ConstraintType end struct FeedforwardIntegralLimitConstraint <: ConstraintType end diff --git a/src/core/variables.jl b/src/core/variables.jl index 7141f4ee6c..5ce9b40321 100644 --- a/src/core/variables.jl +++ b/src/core/variables.jl @@ -104,13 +104,6 @@ struct ActivePowerReserveVariable <: VariableType end struct ServiceRequirementVariable <: VariableType end -""" -Struct to dispatch the creation of energy (water) spillage variable representing energy released from a storage/reservoir not injected into the network - -Docs abbreviation: ``S`` -""" -struct WaterSpillageVariable <: VariableType end - struct StartVariable <: VariableType end struct StopVariable <: VariableType end @@ -204,7 +197,6 @@ convert_result_to_natural_units(::Type{EnergyVariable}) = true convert_result_to_natural_units(::Type{ReactivePowerVariable}) = true convert_result_to_natural_units(::Type{ActivePowerReserveVariable}) = true convert_result_to_natural_units(::Type{ServiceRequirementVariable}) = true -# convert_result_to_natural_units(::Type{WaterSpillageVariable }) = true # TODO: is this pu? convert_result_to_natural_units(::Type{AreaMismatchVariable}) = true convert_result_to_natural_units(::Type{DeltaActivePowerUpVariable}) = true convert_result_to_natural_units(::Type{DeltaActivePowerDownVariable}) = true From 7892278d9c4d682bcbf4d20d07caf6805f9aaacc Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 16:39:07 -0600 Subject: [PATCH 258/370] more hydro removal --- docs/src/api/PowerSimulations.md | 8 ++------ src/PowerSimulations.jl | 2 -- src/core/parameters.jl | 31 ------------------------------- test/test_simulation_results.jl | 2 -- 4 files changed, 2 insertions(+), 41 deletions(-) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index 923befca92..2f8d8e47b4 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -259,19 +259,15 @@ FeedforwardEnergyTargetConstraint # Parameters -### Time Series Parameters +## Time Series Parameters ```@docs ActivePowerTimeSeriesParameter ReactivePowerTimeSeriesParameter RequirementTimeSeriesParameter -EnergyTargetTimeSeriesParameter -EnergyBudgetTimeSeriesParameter -InflowTimeSeriesParameter -OutflowTimeSeriesParameter ``` -### Variable Value Parameters +## Variable Value Parameters ```@docs UpperBoundValueParameter diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 3502ccae0d..d57e4fe717 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -305,8 +305,6 @@ export StartupTimeLimitTemperatureConstraint export ActivePowerTimeSeriesParameter export ReactivePowerTimeSeriesParameter export RequirementTimeSeriesParameter -export EnergyTargetTimeSeriesParameter -export EnergyBudgetTimeSeriesParameter # Feedforward Parameters export OnStatusParameter diff --git a/src/core/parameters.jl b/src/core/parameters.jl index d20f0b40e4..a923e707c5 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -281,26 +281,6 @@ Paramter to define requirement time series """ struct RequirementTimeSeriesParameter <: TimeSeriesParameter end -""" -Parameter to define energy storage target level time series -""" -struct EnergyTargetTimeSeriesParameter <: TimeSeriesParameter end - -""" -Parameter to define energy budget time series -""" -struct EnergyBudgetTimeSeriesParameter <: TimeSeriesParameter end - -""" -Parameter to define energy inflow to storage or reservoir time series -""" -struct InflowTimeSeriesParameter <: TimeSeriesParameter end - -""" -Parameter to define energy outflow from storage or reservoir time series -""" -struct OutflowTimeSeriesParameter <: TimeSeriesParameter end - abstract type VariableValueParameter <: RightHandSideParameter end """ @@ -328,11 +308,6 @@ Parameter to define fixed output values """ struct FixValueParameter <: VariableValueParameter end -""" -Parameter to define energy storage target -""" -struct EnergyTargetParameter <: VariableValueParameter end - """ Parameter to define cost function coefficient """ @@ -348,11 +323,5 @@ convert_result_to_natural_units(::Type{<:ParameterType}) = false convert_result_to_natural_units(::Type{ActivePowerTimeSeriesParameter}) = true convert_result_to_natural_units(::Type{ReactivePowerTimeSeriesParameter}) = true convert_result_to_natural_units(::Type{RequirementTimeSeriesParameter}) = true -convert_result_to_natural_units(::Type{EnergyTargetTimeSeriesParameter}) = true -convert_result_to_natural_units(::Type{EnergyBudgetTimeSeriesParameter}) = true -#convert_result_to_natural_units(::Type{InflowTimeSeriesParameter}) = true # TODO: is this pu? -#convert_result_to_natural_units(::Type{OutflowTimeSeriesParameter}) = true # TODO: is this pu? convert_result_to_natural_units(::Type{UpperBoundValueParameter}) = true convert_result_to_natural_units(::Type{LowerBoundValueParameter}) = true -convert_result_to_natural_units(::Type{EnergyLimitParameter}) = true -convert_result_to_natural_units(::Type{EnergyTargetParameter}) = true diff --git a/test/test_simulation_results.jl b/test/test_simulation_results.jl index 6de5cafbae..afd6d4765b 100644 --- a/test/test_simulation_results.jl +++ b/test/test_simulation_results.jl @@ -81,10 +81,8 @@ NATURAL_UNITS_VALUES = [ "ActivePowerTimeSeriesParameter__HydroEnergyReservoir", "ActivePowerTimeSeriesParameter__RenewableDispatch", "ActivePowerTimeSeriesParameter__InterruptiblePowerLoad", - "EnergyLimitParameter__HydroEnergyReservoir", "SystemBalanceSlackDown__System", "SystemBalanceSlackUp__System", - "EnergyBudgetTimeSeriesParameter__HydroEnergyReservoir", ] function compare_results(rpath, epath, model, field, name, timestamp) From 9ce97ad929ef2cec10bc0dfc1786ab1656544894 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 17:04:30 -0600 Subject: [PATCH 259/370] comment out repeated code with HydroPowerSims --- .../device_constructors/hydrogeneration_constructor.jl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index 75673eba77..5d04b0be29 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -70,6 +70,7 @@ function construct_device!( return end +#= """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation """ @@ -132,6 +133,7 @@ function construct_device!( return end + function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -178,6 +180,7 @@ function construct_device!( return end +=# """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation @@ -191,7 +194,7 @@ function construct_device!( network_model::NetworkModel{S}, ) where { H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, + D <: HydroDispatchRunOfRiver, S <: PM.AbstractActivePowerModel, } devices = @@ -232,6 +235,7 @@ function construct_device!( return end +#= function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -270,6 +274,7 @@ function construct_device!( add_constraint_dual!(container, sys, model) return end +=# """ Construct model for HydroGen with RunOfRiver Commitment Formulation From 448468051bb9d76319906106b32e7323cc8eca83 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 17:11:09 -0600 Subject: [PATCH 260/370] formatter --- .../device_constructors/hydrogeneration_constructor.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index 5d04b0be29..4e504bb613 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -133,7 +133,6 @@ function construct_device!( return end - function construct_device!( container::OptimizationContainer, sys::PSY.System, From 4c7defd1b6c886dc477c30f66617ce514b6e2b24 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 13 Jul 2023 10:47:27 -0600 Subject: [PATCH 261/370] fix hydro tests and references --- docs/src/tutorials/decision_problem.md | 2 +- .../hydrogeneration_constructor.jl | 12 +++++------- src/devices_models/devices/hydro_generation.jl | 9 +-------- src/simulation/simulation_results.jl | 1 - 4 files changed, 7 insertions(+), 17 deletions(-) diff --git a/docs/src/tutorials/decision_problem.md b/docs/src/tutorials/decision_problem.md index 52cc8c4886..584a986811 100644 --- a/docs/src/tutorials/decision_problem.md +++ b/docs/src/tutorials/decision_problem.md @@ -64,7 +64,7 @@ set_device_model!(template_uc, ThermalStandard, ThermalStandardUnitCommitment) set_device_model!(template_uc, RenewableDispatch, RenewableFullDispatch) set_device_model!(template_uc, PowerLoad, StaticPowerLoad) set_device_model!(template_uc, HydroDispatch, FixedOutput) -set_device_model!(template_uc, HydroEnergyReservoir, HydroDispatchRunOfRiver) +set_device_model!(template_uc, HydroDispatchRunOfRiver, HydroDispatchRunOfRiver) set_device_model!(template_uc, RenewableFix, FixedOutput) ``` diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index 4e504bb613..dd43264c65 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -70,7 +70,6 @@ function construct_device!( return end -#= """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation """ @@ -82,7 +81,7 @@ function construct_device!( network_model::NetworkModel{S}, ) where { H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, + D <: Union{HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}, S <: PM.AbstractPowerModel, } devices = @@ -141,7 +140,7 @@ function construct_device!( network_model::NetworkModel{S}, ) where { H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, + D <: Union{HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}, S <: PM.AbstractPowerModel, } devices = @@ -179,7 +178,6 @@ function construct_device!( return end -=# """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation @@ -234,7 +232,7 @@ function construct_device!( return end -#= + function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -243,7 +241,7 @@ function construct_device!( network_model::NetworkModel{S}, ) where { H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, + D <: HydroDispatchRunOfRiver, S <: PM.AbstractActivePowerModel, } devices = @@ -273,7 +271,7 @@ function construct_device!( add_constraint_dual!(container, sys, model) return end -=# + """ Construct model for HydroGen with RunOfRiver Commitment Formulation diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 95cd47efec..34a8ae1de8 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -62,13 +62,6 @@ variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGe #! format: on -function get_initial_conditions_device_model( - ::OperationModel, - model::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroEnergyReservoir} - return model -end - function get_initial_conditions_device_model( ::OperationModel, ::DeviceModel{T, <:AbstractHydroFormulation}, @@ -89,7 +82,7 @@ end function get_default_attributes( ::Type{T}, ::Type{D}, -) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} +) where {T <: PSY.HydroGen, D <:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}} return Dict{String, Any}("reservation" => false) end diff --git a/src/simulation/simulation_results.jl b/src/simulation/simulation_results.jl index 7cbfa5b53c..142f17b5ee 100644 --- a/src/simulation/simulation_results.jl +++ b/src/simulation/simulation_results.jl @@ -230,7 +230,6 @@ An example JSON file demonstrating possible options is below. Note that `start_t "name": "ED", "variables": [ "P__ThermalStandard", - "E__HydroEnergyReservoir" ], "parameters": [ "all" From e5c6b4be30ce98d74783044642d35761a3fcef4b Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 13 Jul 2023 10:50:41 -0600 Subject: [PATCH 262/370] formatter --- .../device_constructors/hydrogeneration_constructor.jl | 2 -- src/devices_models/devices/hydro_generation.jl | 5 ++++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index dd43264c65..534038d7f6 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -232,7 +232,6 @@ function construct_device!( return end - function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -272,7 +271,6 @@ function construct_device!( return end - """ Construct model for HydroGen with RunOfRiver Commitment Formulation """ diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 34a8ae1de8..2767ff8095 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -82,7 +82,10 @@ end function get_default_attributes( ::Type{T}, ::Type{D}, -) where {T <: PSY.HydroGen, D <:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}} +) where { + T <: PSY.HydroGen, + D <: Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}, +} return Dict{String, Any}("reservation" => false) end From 4a8303dd5a97b807811d3e98974c9870a8dff243 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 13 Jul 2023 10:57:12 -0600 Subject: [PATCH 263/370] change abstract type call --- src/devices_models/devices/hydro_generation.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 2767ff8095..9773698f0e 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -65,8 +65,8 @@ variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGe function get_initial_conditions_device_model( ::OperationModel, ::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroDispatch} - return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) +) where {T <: PSY.HydroGen} + return DeviceModel(T, HydroDispatchRunOfRiver) end function get_default_time_series_names( From 517f938c64b9489248c80e71011174ece6f35ef2 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 14 Jul 2023 16:57:01 -0600 Subject: [PATCH 264/370] fix initial condition model --- src/devices_models/devices/hydro_generation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 9773698f0e..f0399d91f1 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -66,7 +66,7 @@ function get_initial_conditions_device_model( ::OperationModel, ::DeviceModel{T, <:AbstractHydroFormulation}, ) where {T <: PSY.HydroGen} - return DeviceModel(T, HydroDispatchRunOfRiver) + return DeviceModel(T, HydroCommitmentRunOfRiver) end function get_default_time_series_names( From 4e950cd934487801cb11edd4d5a79efb0e081f80 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Mon, 17 Jul 2023 16:25:00 -0700 Subject: [PATCH 265/370] return energytargetparameter --- src/core/parameters.jl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index a923e707c5..ea6baa0fa9 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -302,10 +302,9 @@ struct OnStatusParameter <: VariableValueParameter end Parameter to define energy limit """ struct EnergyLimitParameter <: VariableValueParameter end - -""" -Parameter to define fixed output values -""" +# TODO: Check if EnergyTargetParameter and EnergyLimitParameter should be removed +# This affects feedforwards that can break if not defined +struct EnergyTargetParameter <: VariableValueParameter end struct FixValueParameter <: VariableValueParameter end """ @@ -325,3 +324,6 @@ convert_result_to_natural_units(::Type{ReactivePowerTimeSeriesParameter}) = true convert_result_to_natural_units(::Type{RequirementTimeSeriesParameter}) = true convert_result_to_natural_units(::Type{UpperBoundValueParameter}) = true convert_result_to_natural_units(::Type{LowerBoundValueParameter}) = true +# TODO: Check if EnergyLimitParameter and EnergyTargetParameter should be removed +convert_result_to_natural_units(::Type{EnergyLimitParameter}) = true +convert_result_to_natural_units(::Type{EnergyTargetParameter}) = true From 6271279756c99519f5ce5baf41c81e42d5a220fc Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 9 Aug 2023 11:35:10 -0600 Subject: [PATCH 266/370] address PR comments --- .../structure_of_operation_problem.md | 2 +- docs/src/modeler_guide/running_a_simulation.md | 4 +++- docs/src/tutorials/adding_new_problem_model.md | 12 ++++++------ src/operation/decision_model.jl | 4 ++-- src/operation/emulation_model.jl | 4 ++-- test/Project.toml | 5 +++-- 6 files changed, 17 insertions(+), 14 deletions(-) diff --git a/docs/src/model_developer_guide/structure_of_operation_problem.md b/docs/src/model_developer_guide/structure_of_operation_problem.md index b4d67b51d0..202bbe0cb0 100644 --- a/docs/src/model_developer_guide/structure_of_operation_problem.md +++ b/docs/src/model_developer_guide/structure_of_operation_problem.md @@ -1,7 +1,7 @@ # Structure of an operations problem model In most cases operation problem models are optimization models. Although in `PowerSimulations.jl` it is -possible to define arbitrary problems that can reflect heuristic decision rules, this is not the common case. This page focuses on explaining the structure of operations problems that employ and optimization problem and solver. +possible to define arbitrary problems that can reflect heuristic decision rules, this is not the common case. This page focuses on explaining the structure of operations problems that employ an optimization problem and solver. The first aspect to consider when thinking about developing a model compatible with `PowerSimulations.jl` is that although we support all of `JuMP.jl` objects, you need to employ [anonymous constraints and variables in JuMP](https://jump.dev/JuMP.jl/stable/manual/variables/#anonymous_variables) and register the constraints, variables and other optimization objects into PowerSimulations.jl's optimization container. Otherwise the features to use your problem in the simulation like the coordination with other problems and post processing won't work. diff --git a/docs/src/modeler_guide/running_a_simulation.md b/docs/src/modeler_guide/running_a_simulation.md index c0fe63b512..906bff25a2 100644 --- a/docs/src/modeler_guide/running_a_simulation.md +++ b/docs/src/modeler_guide/running_a_simulation.md @@ -11,4 +11,6 @@ TODO ## Sequencing -TODO +In a typical simulation pipeline, we want to connect daily (24-hours) day-ahead unit commitment problems, with multiple economic dispatch problems. Usually, our day-ahead unit commitment problem will have an hourly (1-hour) resolution, while the economic dispatch will have a 5-minute resolution. + +Depending on your problem, it is common to use a 2-day look-ahead for unit commitment problems, so in this case, the Day-Ahead problem will have: resolution = Hour(1) with interval = Hour(24) and horizon = 48. In the case of the economic dispatch problem, it is common to use a look-ahead of two hours. Thus, the Real-Time problem will have: resolution = Minute(5), with interval = Minute(5) (we only store the first operating point) and horizon = 24 (24 time steps of 5 minutes are 120 minutes, that is 2 hours). diff --git a/docs/src/tutorials/adding_new_problem_model.md b/docs/src/tutorials/adding_new_problem_model.md index 0134dd58b4..795a3f1111 100644 --- a/docs/src/tutorials/adding_new_problem_model.md +++ b/docs/src/tutorials/adding_new_problem_model.md @@ -6,22 +6,22 @@ where the user want to solve a fully specified problem. Some examples of custom - Solving a custom Security Constrained Unit Commitment Problem - Solving a market agent utility maximization Problem. See examples of this functionality in HybridSystemsSimulations.jl -The tutorial follows the usual steps for operational model building. First, build the decision model in isolation and second integrate int a simulation. In most cases there will be more than one way of achieving +The tutorial follows the usual steps for operational model building. First, build the decision model in isolation and second, integrate it into a simulation. In most cases there will be more than one way of achieving the same objective when it comes to implementing the model. This guide shows a general set of steps and requirements but it is by no means an exhaustive and detailed guide on developing custom decision models. !!! warning - All the code in this tutorial is considered "pseudo-code". If you copy-paste will likely not work out of the box. You need to develop the internals of the functions correctly for the examples below to work. + All the code in this tutorial is considered "pseudo-code". Copy-paste will likely not work out of the box. You need to develop the internals of the functions correctly for the examples below to work. ## General Rules -1. As a general rule you need to understand Julia's terminology such as multiple dispatch, parametried structs and method overloading among others. Developing custom models for an operational simulation is highly technical task and requires skilled development. This tuturial also requires good understanding of PowerSystems.jl data structures and features which are covered in the tutorials section of PowerSystems.jl documentation. +1. As a general rule you need to understand Julia's terminology such as multiple dispatch, parametric structs and method overloading, among others. Developing custom models for an operational simulation is a highly technical task and requires skilled development. This tutorial also requires good understanding of PowerSystems.jl data structures and features which are covered in the tutorials section of PowerSystems.jl documentation. Finally, developing a custom model decision model that will employ an optimization model under the hood requires understanding JuMP.jl. 2. Need to employ [anonymous constraints and variables in JuMP](https://jump.dev/JuMP.jl/stable/manual/variables/#anonymous_variables) and register the constraints, variables and other optimization objects into PowerSimulations.jl's optimization container. Otherwise the features to use your problem in the simulation like the coordination with other problems and post processing won't work. More on this in the section [How to develop your `build_model!` function](@ref) below. -3. Overload the required methods for your custom decision models. In some cases it will be possible to re-use some of the other methods that exist in PowerSimulations to make life easier for variable addition and constraint creation but this is not required. +3. Implement the required methods for your custom decision models. In some cases it will be possible to re-use some of the other methods that exist in PowerSimulations to make life easier for variable addition and constraint creation but this is not required. ## Decision Problem @@ -30,7 +30,7 @@ features to use your problem in the simulation like the coordination with other Define a decision problem struct as a subtype of `PowerSimulations.DecisionProblem`. This requirement will enable a lot of the underlying functionality that relies on multiple dispatch. DecisionProblems are used to parameterize the behavior of `DecisionModel` objects which are just containers for the parameters, references and the optimization problem. -It is possible to define a Custom Decision Problem that gives the user full control over the build, solve and execution process since it imposes less requirements on the developer. However, with less requirements there are also less check and validations performed inside of PowerSimulations which might lead to unexpected erros. +It is possible to define a Custom Decision Problem that gives the user full control over the build, solve and execution process since it imposes less requirements on the developer. However, with less requirements there are also less checks and validations performed inside of PowerSimulations which might lead to unexpected errors ```julia struct MyCustomDecisionProblem <: PSI.DecisionProblem end @@ -53,7 +53,7 @@ my_model = DecisionModel{MyCustomDecisionProblem}( ) ``` -#### Mandatory Method Overloads +#### Mandatory Method Implementations 1. `build_model!`: This method build the `JuMP` optimization model. diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index 20403486a2..8287346b53 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -16,7 +16,7 @@ struct GenericOpProblem <: DefaultDecisionProblem end jump_model::Union{Nothing, JuMP.Model}=nothing; kwargs...) where {M<:DecisionProblem} -Builds the optimization problem of type M with the specific system and template. +Build the optimization problem of type M with the specific system and template. # Arguments @@ -136,7 +136,7 @@ function DecisionModel{M}( end """ -Builds the optimization problem of type M with the specific system and template +Build the optimization problem of type M with the specific system and template # Arguments diff --git a/src/operation/emulation_model.jl b/src/operation/emulation_model.jl index 2186f8de4d..0f27b8ddc4 100644 --- a/src/operation/emulation_model.jl +++ b/src/operation/emulation_model.jl @@ -16,7 +16,7 @@ struct GenericEmulationProblem <: DefaultEmulationProblem end jump_model::Union{Nothing, JuMP.Model}=nothing; kwargs...) where {M<:EmulationProblem} -Builds the optimization problem of type M with the specific system and template. +Build the optimization problem of type M with the specific system and template. # Arguments @@ -126,7 +126,7 @@ function EmulationModel{M}( end """ -Builds the optimization problem of type M with the specific system and template +Build the optimization problem of type M with the specific system and template # Arguments diff --git a/test/Project.toml b/test/Project.toml index 72c8c475a9..2b72548673 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -7,6 +7,7 @@ DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" GLPK = "60bf3e95-4087-53dc-ae20-288a0d20c6a6" HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b" +HydroPowerSimulations = "fc1677e0-6ad7-4515-bf3a-bd6bf20a0b1b" InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1" Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9" JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" @@ -30,6 +31,6 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [compat] HiGHS = "=1.1.2" -julia = "^1.6" -PowerSystemCaseBuilder = "~1.0.2" Ipopt = "=1.4.0" +PowerSystemCaseBuilder = "~1.0.2" +julia = "^1.6" From a262204e157167514c8e31d1003ea685af09f53a Mon Sep 17 00:00:00 2001 From: Daniel Thom Date: Wed, 9 Aug 2023 13:05:27 -0600 Subject: [PATCH 267/370] Fix bug in custom indexing for realized results This bug was introduced in commit 21f6dff464b322f4785a426ef6dd215082ed0510. Passing custom values of start_time and len that cause the code to span arrays from two initial times caused an array indexing error. --- src/simulation/realized_meta.jl | 7 ++++--- test/test_simulation_results.jl | 11 +++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/simulation/realized_meta.jl b/src/simulation/realized_meta.jl index e0344146fe..3b8f9c34ea 100644 --- a/src/simulation/realized_meta.jl +++ b/src/simulation/realized_meta.jl @@ -59,6 +59,7 @@ function get_realization( columns = get_column_names(results_by_time) num_cols = length(columns) matrix = Matrix{Float64}(undef, num_rows, num_cols) + row_index = 1 for (step, (_, array)) in enumerate(results_by_time) first_id = step > 1 ? 1 : meta.start_offset last_id = @@ -69,9 +70,9 @@ function get_realization( Can't calculate the realized variables. Use `read_variables` instead and write your own concatenation", ) end - row_start = (step - 1) * meta.interval_len + 1 - row_end = row_start + last_id - first_id - matrix[row_start:row_end, :] = array[first_id:last_id, :] + row_end = row_index + last_id - first_id + matrix[row_index:row_end, :] = array[first_id:last_id, :] + row_index += last_id - first_id + 1 end df = DataFrames.DataFrame(matrix, collect(columns); copycols = false) DataFrames.insertcols!( diff --git a/test/test_simulation_results.jl b/test/test_simulation_results.jl index 6de5cafbae..9080afd737 100644 --- a/test/test_simulation_results.jl +++ b/test/test_simulation_results.jl @@ -311,6 +311,17 @@ function test_decision_problem_results_values( @test size(var)[1] == 48 end + # Test custom indexing. + realized_variable_uc2 = + read_realized_variables( + results_uc, + [(ActivePowerVariable, ThermalStandard)]; + start_time = Dates.DateTime("2024-01-01T01:00:00"), + len = 47, + ) + @test realized_variable_uc["ActivePowerVariable__ThermalStandard"][2:end, :] == + realized_variable_uc2["ActivePowerVariable__ThermalStandard"] + realized_param_uc = read_realized_parameters(results_uc) @test length(keys(realized_param_uc)) == 3 for param in values(realized_param_uc) From 3940fa7f87f4e08bbc9325a4210b3e7d5837c140 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 9 Aug 2023 13:47:46 -0600 Subject: [PATCH 268/370] export the serialize functions for the problems --- src/PowerSimulations.jl | 1 + src/operation/operation_model_interface.jl | 8 ++++++++ src/utils/jump_utils.jl | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index d57e4fe717..34e475a00b 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -181,6 +181,7 @@ export get_realized_timestamps export get_problem_base_power export get_objective_value export read_optimizer_stats +export serialize_optimization_model ## Utils Exports export get_all_constraint_index diff --git a/src/operation/operation_model_interface.jl b/src/operation/operation_model_interface.jl index 53aae2f0fb..75ccd2bd56 100644 --- a/src/operation/operation_model_interface.jl +++ b/src/operation/operation_model_interface.jl @@ -393,3 +393,11 @@ function list_all_keys(x::OperationModel) keys(get_data_field(get_store(x), f)) for f in STORE_CONTAINERS ) end + +function serialize_optimization_model(model::OperationModel, save_path::String) + serialize_jump_optimization_model( + get_optimization_container(model), + save_path, + ) + return +end diff --git a/src/utils/jump_utils.jl b/src/utils/jump_utils.jl index 22ee166e56..2fe99a0cca 100644 --- a/src/utils/jump_utils.jl +++ b/src/utils/jump_utils.jl @@ -300,7 +300,7 @@ end """ Exports the JuMP object in MathOptFormat """ -function serialize_optimization_model(jump_model::JuMP.Model, save_path::String) +function serialize_jump_optimization_model(jump_model::JuMP.Model, save_path::String) MOF_model = MOPFM(; format = MOI.FileFormats.FORMAT_MOF) MOI.copy_to(MOF_model, JuMP.backend(jump_model)) MOI.write_to_file(MOF_model, save_path) From 05af7e22f89662e5b265cafd02b4e934c71ae767 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 9 Aug 2023 13:48:07 -0600 Subject: [PATCH 269/370] some updates to definitions --- docs/src/modeler_guide/definitions.md | 4 +++- docs/src/tutorials/decision_problem.md | 15 ++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/src/modeler_guide/definitions.md b/docs/src/modeler_guide/definitions.md index 77a91065e0..8a4946f85f 100644 --- a/docs/src/modeler_guide/definitions.md +++ b/docs/src/modeler_guide/definitions.md @@ -2,7 +2,9 @@ ## D -* *Decision Problem*: A decision problem calculates the desired system operation based on forecasts of uncertain inputs and information about the state of the system. The output of a decision problem represents the policies used to drive the set-points of the system's devices, like generators or switches, and depends on the purpose of the problem. +* *Decision Problem*: A decision problem calculates the desired system operation based on forecasts of uncertain inputs and information about the state of the system. The output of a decision problem represents the policies used to drive the set-points of the system's devices, like generators or switches, and depends on the purpose of the problem. See the [Decision Model Tutorial](op_problem_tutorial) to learn more about solving individual problems. + +* *Device Formulation*: The model of a device that is incorporated into a large system optimization models. For instance, the storage device model used inside of a Unit Commitment (UC) problem. A device model needs to follow some requirements to be integrated into operation problems. ## E diff --git a/docs/src/tutorials/decision_problem.md b/docs/src/tutorials/decision_problem.md index 584a986811..896e105639 100644 --- a/docs/src/tutorials/decision_problem.md +++ b/docs/src/tutorials/decision_problem.md @@ -19,8 +19,9 @@ using HiGHS # solver ## Data -This data depends upon the [RTS-GMLC](https://github.com/gridmod/rts-gmlc) dataset. Let's -use [PowerSystemCaseBuilder.jl](https://github.com/nrel-sienna/powersystemcasebuilder.jl) to download and build a `System`. +!!! 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 Documentation](https://nrel-sienna.github.io/PowerSystems.jl/stable/tutorials/powersystembuilder/) ```@example op_problem sys = build_system(PSISystems, "modified_RTS_GMLC_DA_sys") @@ -40,8 +41,8 @@ and the subtypes of `AbstractDeviceFormulation`. PowerSimulations has a variety each dispatching to different methods for populating optimization problem objectives, variables, and constraints. Documentation on the formulation options for various devices can be found in the [formulation library docs](https://nrel-sienna.github.io/PowerSimulations.jl/latest/formulation_library/General/#formulation_library) - ### Branch Formulations + Here is an example of relatively standard branch formulations. Other formulations allow for selective enforcement of transmission limits and greater control on transformer settings. @@ -117,13 +118,9 @@ build!(problem, output_dir = mktempdir()) ``` !!! tip - The principal component of the `DecisionModel` is the JuMP model. For small problems, you can inspect it by simply printing it to the screen: - ```julia jump_model - print(PowerSimulations.get_jump_model(problem)) - ``` - For anything of reasonable size, that will be unmanageable. But you can print to a file: + The principal component of the `DecisionModel` is the JuMP model. But you can print to a file: ```julia - f = open("testmodel.txt","w"); print(f,PowerSimulations.get_jump_model(problem)); close(f) + serialize_optimization_model(problem, save_path) ``` ### Solve an `DecisionModel` From a2fdc104c4b423ffc476941fbfc7455c59a71c8c Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 9 Aug 2023 15:25:58 -0600 Subject: [PATCH 270/370] update to decision models docs --- docs/src/tutorials/decision_problem.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/src/tutorials/decision_problem.md b/docs/src/tutorials/decision_problem.md index 896e105639..eaa60e6b0b 100644 --- a/docs/src/tutorials/decision_problem.md +++ b/docs/src/tutorials/decision_problem.md @@ -118,10 +118,11 @@ build!(problem, output_dir = mktempdir()) ``` !!! tip - The principal component of the `DecisionModel` is the JuMP model. But you can print to a file: + The principal component of the `DecisionModel` is the JuMP model. But you can serialize to a file using the following command: ```julia serialize_optimization_model(problem, save_path) ``` + Keep in mind that if the setting "store_variable_names" is set to `False` then the file won't show the model's names. ### Solve an `DecisionModel` From a6de3ac2616882ef1dbfb67c5208d06e64448ca9 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 10 Aug 2023 11:18:33 -0600 Subject: [PATCH 271/370] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index b5c54293ec..c14ac8467e 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "PowerSimulations" uuid = "e690365d-45e2-57bb-ac84-44ba829e73c4" authors = ["Jose Daniel Lara", "Clayton Barrows", "Daniel Thom", "Dheepak Krishnamurthy", "Sourabh Dalvi"] -version = "0.21.2" +version = "0.21.3" [deps] CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" From fbf6a7b12564a79647123e8f4114298aa7b76e6f Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 14 Aug 2023 09:07:42 -0600 Subject: [PATCH 272/370] docs improvements --- .../structure_of_operation_problem.md | 40 ++++++++ .../src/tutorials/adding_new_problem_model.md | 91 +++++++++++++++++-- 2 files changed, 123 insertions(+), 8 deletions(-) diff --git a/docs/src/model_developer_guide/structure_of_operation_problem.md b/docs/src/model_developer_guide/structure_of_operation_problem.md index 202bbe0cb0..8b793d7948 100644 --- a/docs/src/model_developer_guide/structure_of_operation_problem.md +++ b/docs/src/model_developer_guide/structure_of_operation_problem.md @@ -8,3 +8,43 @@ and register the constraints, variables and other optimization objects into Powe !!! info The requirements for the simulation of Power Systems operations are more strict than solving an optimization problem once with just `JuMP.jl`. The requirements imposed by `PowerSimulations.jl` to integrate your models in a simulation are designed to help with other complex operations that go beyond `JuMP.jl` scope. + +!!! warning + All the code in this page is considered "pseudo-code". Copy-paste will likely not work out of the box. You need to develop the internals of the functions correctly for the examples below to work. + +## Registering a variable in the model + +To register a variable in the model, the developer must first allocate the container into the +optimization container and then populate it. For example, it require start the build function as follows: + +!!! info + We recommend calling `import PowerSimulations` and defining the constant `CONST PSI = PowerSimulations` to + make it easier to read the code and determine which package is responsible for defining the functions. + +```julia + function PSI.build_model!(model::PSI.DecisionModel{MyCustomModel}) + container = PSI.get_optimization_container(model) + PSI.set_time_steps!(container, 1:24) + + # Create the container for the variable + variable = PSI.add_variable_container!( + container, + PSI.ActivePowerVariable(), # <- This variable is defined in PowerSimulations but the user can define their own + PSY.ThermalGeneration, # <- Device type for the variable. Can be from PSY or custom defined + devices_names, # <- First container dimension + time_steps, # <- Second container dimension + ) + + # Iterate over the devices and time to store the JuMP variables into the container. + for t in time_steps, d in devices + name = PSY.get_name(d) + variable[name, t] = JuMP.@variable(get_jump_model(container)) + # It is possible to use PSY getter functions to retrieve data from the generators + # Any other variable property can be specified inside this loop. + JuMP.set_upper_bound(variable[name, t], UB_DATA) # <- Optional + JuMP.set_lower_bound(variable[name, t], LB_DATA) # <- Optional + end + + return + end +``` diff --git a/docs/src/tutorials/adding_new_problem_model.md b/docs/src/tutorials/adding_new_problem_model.md index 795a3f1111..ab81f6ed04 100644 --- a/docs/src/tutorials/adding_new_problem_model.md +++ b/docs/src/tutorials/adding_new_problem_model.md @@ -68,18 +68,93 @@ These methods can be defined optionally for your problem. By default for problem ### How to develop your `build_model!` function +#### Registering a variable in the model +To register a variable in the model, the developer must first allocate the container into the +optimization container and then populate it. For example, it require start the build function as follows: + +!!! info + We recommend calling `import PowerSimulations` and defining the constant `CONST PSI = PowerSimulations` to + make it easier to read the code and determine which package is responsible for defining the functions. ```julia -function PSI.build_model!(model::PSI.DecisionModel{MyCustomDecisionProblem}) - container = PSI.get_optimization_container(model) - PSI.set_time_steps!(container, 1:24) # <- Mandatory - system = PSI.get_system(model) + function PSI.build_model!(model::PSI.DecisionModel{MyCustomDecisionProblem}) + container = PSI.get_optimization_container(model) + time_steps = 1:24 + PSI.set_time_steps!(container, time_steps) + system = PSI.get_system(model) + + thermal_gens = PSY.get_components(PSY.ThermalStandard, system) + thermal_gens_names = PSY.get_name.(thermal_gens) + + # Create the container for the variable + variable = PSI.add_variable_container!( + container, + PSI.ActivePowerVariable(), # <- This variable is defined in PowerSimulations but the user can define their own + PSY.ThermalGeneration, # <- Device type for the variable. Can be from PSY or custom defined + thermal_gens_names, # <- First container dimension + time_steps, # <- Second container dimension + ) + + # Iterate over the devices and time to store the JuMP variables into the container. + for t in time_steps, d in thermal_gens_names + name = PSY.get_name(d) + variable[name, t] = JuMP.@variable(get_jump_model(container)) + # It is possible to use PSY getter functions to retrieve data from the generators + JuMP.set_upper_bound(variable[name, t], UB_DATA) # <- Optional + JuMP.set_lower_bound(variable[name, t], LB_DATA) # <- Optional + end + + # Add More Variables..... + + return + end +``` +#### Registering a constraint in the model +A similar pattern is used to add constraints to the model, in this example the field `meta` is used +to avoid creating unnecessary duplicate constraint types. For instance to reflect upper_bound and lower_bound or upwards and downwards constraints. Meta can take any string value except for the `_` character. - update_objective_function!(container) # <- Mandatory -end +```julia + function PSI.build_model!(model::PSI.DecisionModel{MyCustomDecisionProblem}) + container = PSI.get_optimization_container(model) + time_steps = 1:24 + PSI.set_time_steps!(container, time_steps) + system = PSI.get_system(model) + + # VARIABLE ADDITION CODE + + # Constraint additions + con_ub = PSI.add_constraints_container!( + container, + PSI.RangeLimitConstraint(), # <- Constraint Type defined by PSI or your own + PSY.ThermalGeneration, # <- Device type for variable. Can be PSY or custom + thermal_gens_names, # <- First container dimension + time_steps; # <- Second container dimension + meta = "ub" # <- meta allows to reuse a constraint definition for similar constraints. It only requires to be a string + ) + + con_lb = PSI.add_constraints_container!( + container, + PSI.RangeLimitConstraint(), + PSY.ThermalGeneration, + thermal_gens_names, # <- First container dimension + time_steps; # <- Second container dimension + meta = "lb" # <- meta allows to reuse a constraint definition for similar constraints. It only requires to be a string + ) + + # Retrieve a relevant variable from the container if not defined in + variable = PSI.get_variable(container, PSI.ActivePowerVariable(), PSY.ThermalGeneration) + for device in devices, t in time_steps + ci_name = PSY.get_name(device) + limits = get_min_max_limits(device) # depends on constraint type and formulation type + con_ub[ci_name, t] = + JuMP.@constraint(get_jump_model(container), variable[ci_name, t] >= limits.min) + con_lb[ci_name, t] = + JuMP.@constraint(get_jump_model(container), variable[ci_name, t] >= limits.min) + end + + return + end ``` - -## Emulation Problem From 51ad99cc44dc1a465b97469666ce498e3d34f8c5 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 14 Aug 2023 09:10:08 -0600 Subject: [PATCH 273/370] other improvements --- src/PowerSimulations.jl | 3 --- src/core/constraints.jl | 9 ++------- src/core/optimization_container.jl | 2 +- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 34e475a00b..f8f0a25438 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -274,10 +274,7 @@ export FlowReactivePowerToFromConstraint export FrequencyResponseConstraint export HVDCPowerBalance export HVDCLosses -export InflowRangeConstraint export InputActivePowerVariableLimitsConstraint -export InputPowerRangeConstraint -export InterConnectionLimitConstraint export NetworkFlowConstraint export NodalBalanceActiveConstraint export NodalBalanceReactiveConstraint diff --git a/src/core/constraints.jl b/src/core/constraints.jl index f48ad59795..ad89d11187 100644 --- a/src/core/constraints.jl +++ b/src/core/constraints.jl @@ -26,8 +26,6 @@ end Base.convert(::Type{ConstraintKey}, name::Symbol) = ConstraintKey(decode_symbol(name)...) struct AbsoluteValueConstraint <: ConstraintType end -struct ActiveConstraint <: ConstraintType end -struct ActiveRangeConstraint <: ConstraintType end #not being used struct ActiveRangeICConstraint <: ConstraintType end struct AreaDispatchBalanceConstraint <: ConstraintType end struct AreaParticipationAssignmentConstraint <: ConstraintType end @@ -56,9 +54,6 @@ struct FlowReactivePowerFromToConstraint <: ConstraintType end #not being used struct FlowReactivePowerToFromConstraint <: ConstraintType end #not being used struct HVDCPowerBalance <: ConstraintType end struct FrequencyResponseConstraint <: ConstraintType end -struct InflowRangeConstraint <: ConstraintType end #not being used -struct InputPowerRangeConstraint <: ConstraintType end #not being used -struct InterConnectionLimitConstraint <: ConstraintType end #not being used struct NetworkFlowConstraint <: ConstraintType end struct NodalBalanceActiveConstraint <: ConstraintType end struct NodalBalanceReactiveConstraint <: ConstraintType end @@ -74,8 +69,8 @@ struct RegulationLimitsConstraint <: ConstraintType end struct RequirementConstraint <: ConstraintType end struct ReserveEnergyCoverageConstraint <: ConstraintType end struct ReservePowerConstraint <: ConstraintType end -struct SACEPIDAreaConstraint <: ConstraintType end #not being used -struct StartTypeConstraint <: ConstraintType end #not being used +struct SACEPIDAreaConstraint <: ConstraintType end +struct StartTypeConstraint <: ConstraintType end struct StartupInitialConditionConstraint <: ConstraintType end struct StartupTimeLimitTemperatureConstraint <: ConstraintType end struct PhaseAngleControlLimit <: ConstraintType end diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index eb0cb5b93c..769d78a1ea 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -699,7 +699,7 @@ end Exports the OpModel JuMP object in MathOptFormat """ function serialize_optimization_model(container::OptimizationContainer, save_path::String) - serialize_optimization_model(get_jump_model(container), save_path) + serialize_jump_optimization_model(get_jump_model(container), save_path) return end From 595f63a542acd8929b82bb1fb054d287f8bbae50 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 14 Aug 2023 09:19:32 -0600 Subject: [PATCH 274/370] remove ActiveConstraint references --- docs/src/api/PowerSimulations.md | 1 - src/PowerSimulations.jl | 1 - 2 files changed, 2 deletions(-) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index 2f8d8e47b4..c038a7d6c1 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -179,7 +179,6 @@ PieceWiseLinearCostConstraint ### Network Constraints ```@docs -ActiveConstraint AreaDispatchBalanceConstraint AreaParticipationAssignmentConstraint BalanceAuxConstraint diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index f8f0a25438..ffe1cd98b7 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -243,7 +243,6 @@ export EnergyOutput # Constraints export AbsoluteValueConstraint -export ActiveConstraint export ActivePowerVariableLimitsConstraint export ActivePowerVariableTimeSeriesLimitsConstraint export ActiveRangeICConstraint From 7f0e4d027ac612c04a5108e31325730466a4ef6a Mon Sep 17 00:00:00 2001 From: pesap Date: Thu, 24 Aug 2023 17:26:34 -0600 Subject: [PATCH 275/370] Removing Hydro related stuff. --- src/PowerSimulations.jl | 2 +- src/core/formulations.jl | 26 +- .../hydrogeneration_constructor.jl | 936 +++++++++--------- .../devices/hydro_generation.jl | 589 +++++------ ...st_device_hydro_generation_constructors.jl | 121 --- 5 files changed, 778 insertions(+), 896 deletions(-) delete mode 100644 test/test_device_hydro_generation_constructors.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 2fc2a5b2b6..f8c7d4c1d8 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -70,7 +70,7 @@ export DeviceLimitedRegulation export ReserveLimitedRegulation ###### Hydro ####### -export HydroDispatchRunOfRiver +# export HydroDispatchRunOfRiver export HydroCommitmentRunOfRiver # feedforward models diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 6752ad5599..4fefb8d6f1 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -73,19 +73,19 @@ Formulation type to enable (continuous) load interruption dispatch struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end ############################ Hydro Generation Formulations ################################# -abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end -abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end -abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end - -""" -Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` -""" -struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end - -""" -Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` -""" -struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end +# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end +# abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end +# abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end + +# """ +# Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` +# """ +# struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end + +# """ +# Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` +# """ +# struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index 75673eba77..c1ed64385f 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -1,468 +1,468 @@ -""" -Construct model for HydroGen with FixedOutput Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -function construct_device!( - ::OptimizationContainer, - ::PSY.System, - ::ModelConstructStage, - ::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - # FixedOutput doesn't add any constraints to the model. This function covers - # AbstractPowerModel and AbstractActivePowerModel - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -""" -Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end +# """ +# Construct model for HydroGen with FixedOutput Formulation +# """ +# function construct_device!( +# container::OptimizationContainer, +# sys::PSY.System, +# ::ArgumentConstructStage, +# model::DeviceModel{H, FixedOutput}, +# network_model::NetworkModel{S}, +# ) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} +# devices = +# get_available_components(H, sys, get_attribute(model, "filter_function")) +# +# add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) +# add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) +# +# # Expression +# add_to_expression!( +# container, +# ActivePowerBalance, +# ActivePowerTimeSeriesParameter, +# devices, +# model, +# network_model, +# ) +# add_to_expression!( +# container, +# ReactivePowerBalance, +# ReactivePowerTimeSeriesParameter, +# devices, +# model, +# network_model, +# ) +# return +# end +# +# function construct_device!( +# ::OptimizationContainer, +# ::PSY.System, +# ::ModelConstructStage, +# ::DeviceModel{H, FixedOutput}, +# network_model::NetworkModel{S}, +# ) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} +# # FixedOutput doesn't add any constraints to the model. This function covers +# # AbstractPowerModel and AbstractActivePowerModel +# return +# end +# +# function construct_device!( +# container::OptimizationContainer, +# sys::PSY.System, +# ::ArgumentConstructStage, +# model::DeviceModel{H, FixedOutput}, +# network_model::NetworkModel{S}, +# ) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} +# devices = +# get_available_components(H, sys, get_attribute(model, "filter_function")) +# +# add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) +# +# # Expression +# add_to_expression!( +# container, +# ActivePowerBalance, +# ActivePowerTimeSeriesParameter, +# devices, +# model, +# network_model, +# ) +# return +# end +# +# """ +# Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation +# """ +# function construct_device!( +# container::OptimizationContainer, +# sys::PSY.System, +# ::ArgumentConstructStage, +# model::DeviceModel{H, D}, +# network_model::NetworkModel{S}, +# ) where { +# H <: PSY.HydroGen, +# D <: AbstractHydroDispatchFormulation, +# S <: PM.AbstractPowerModel, +# } +# devices = +# get_available_components(H, sys, get_attribute(model, "filter_function")) +# +# add_variables!(container, ActivePowerVariable, devices, D()) +# add_variables!(container, ReactivePowerVariable, devices, D()) +# add_variables!(container, EnergyOutput, devices, D()) +# add_to_expression!( +# container, +# ActivePowerBalance, +# ActivePowerVariable, +# devices, +# model, +# network_model, +# ) +# add_to_expression!( +# container, +# ReactivePowerBalance, +# ReactivePowerVariable, +# devices, +# model, +# network_model, +# ) +# +# add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) +# +# add_expressions!(container, ProductionCostExpression, devices, model) +# +# add_to_expression!( +# container, +# ActivePowerRangeExpressionLB, +# ActivePowerVariable, +# devices, +# model, +# network_model, +# ) +# add_to_expression!( +# container, +# ActivePowerRangeExpressionUB, +# ActivePowerVariable, +# devices, +# model, +# network_model, +# ) +# +# add_feedforward_arguments!(container, model, devices) +# return +# end +# +# function construct_device!( +# container::OptimizationContainer, +# sys::PSY.System, +# ::ModelConstructStage, +# model::DeviceModel{H, D}, +# network_model::NetworkModel{S}, +# ) where { +# H <: PSY.HydroGen, +# D <: AbstractHydroDispatchFormulation, +# S <: PM.AbstractPowerModel, +# } +# devices = +# get_available_components(H, sys, get_attribute(model, "filter_function")) +# +# add_constraints!( +# container, +# ActivePowerVariableLimitsConstraint, +# ActivePowerRangeExpressionLB, +# devices, +# model, +# network_model, +# ) +# add_constraints!( +# container, +# ActivePowerVariableLimitsConstraint, +# ActivePowerRangeExpressionUB, +# devices, +# model, +# network_model, +# ) +# +# add_constraints!( +# container, +# ReactivePowerVariableLimitsConstraint, +# ReactivePowerVariable, +# devices, +# model, +# network_model, +# ) +# add_feedforward_constraints!(container, model, devices) +# +# objective_function!(container, devices, model, S) +# add_constraint_dual!(container, sys, model) +# +# return +# end +# +# """ +# Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation +# with only Active Power. +# """ +# function construct_device!( +# container::OptimizationContainer, +# sys::PSY.System, +# ::ArgumentConstructStage, +# model::DeviceModel{H, D}, +# network_model::NetworkModel{S}, +# ) where { +# H <: PSY.HydroGen, +# D <: AbstractHydroDispatchFormulation, +# S <: PM.AbstractActivePowerModel, +# } +# devices = +# get_available_components(H, sys, get_attribute(model, "filter_function")) +# +# add_variables!(container, ActivePowerVariable, devices, D()) +# add_variables!(container, EnergyOutput, devices, D()) +# add_to_expression!( +# container, +# ActivePowerBalance, +# ActivePowerVariable, +# devices, +# model, +# network_model, +# ) +# +# add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) +# add_to_expression!( +# container, +# ActivePowerRangeExpressionLB, +# ActivePowerVariable, +# devices, +# model, +# network_model, +# ) +# add_to_expression!( +# container, +# ActivePowerRangeExpressionUB, +# ActivePowerVariable, +# devices, +# model, +# network_model, +# ) +# +# add_expressions!(container, ProductionCostExpression, devices, model) +# +# add_feedforward_arguments!(container, model, devices) +# return +# end +# +# function construct_device!( +# container::OptimizationContainer, +# sys::PSY.System, +# ::ModelConstructStage, +# model::DeviceModel{H, D}, +# network_model::NetworkModel{S}, +# ) where { +# H <: PSY.HydroGen, +# D <: AbstractHydroDispatchFormulation, +# S <: PM.AbstractActivePowerModel, +# } +# devices = +# get_available_components(H, sys, get_attribute(model, "filter_function")) +# +# add_constraints!( +# container, +# ActivePowerVariableLimitsConstraint, +# ActivePowerRangeExpressionLB, +# devices, +# model, +# network_model, +# ) +# add_constraints!( +# container, +# ActivePowerVariableLimitsConstraint, +# ActivePowerRangeExpressionUB, +# devices, +# model, +# network_model, +# ) +# +# add_feedforward_constraints!(container, model, devices) +# +# objective_function!(container, devices, model, S) +# +# add_constraint_dual!(container, sys, model) +# return +# end +# +# """ +# Construct model for HydroGen with RunOfRiver Commitment Formulation +# """ +# function construct_device!( +# container::OptimizationContainer, +# sys::PSY.System, +# ::ArgumentConstructStage, +# model::DeviceModel{H, D}, +# network_model::NetworkModel{S}, +# ) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} +# devices = +# get_available_components(H, sys, get_attribute(model, "filter_function")) +# +# add_variables!(container, ActivePowerVariable, devices, D()) +# add_variables!(container, ReactivePowerVariable, devices, D()) +# add_variables!(container, OnVariable, devices, D()) +# add_variables!(container, EnergyOutput, devices, D()) +# add_to_expression!( +# container, +# ActivePowerBalance, +# ActivePowerVariable, +# devices, +# model, +# network_model, +# ) +# +# add_to_expression!( +# container, +# ReactivePowerBalance, +# ReactivePowerVariable, +# devices, +# model, +# network_model, +# ) +# +# add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) +# +# add_expressions!(container, ProductionCostExpression, devices, model) +# +# add_to_expression!( +# container, +# ActivePowerRangeExpressionLB, +# ActivePowerVariable, +# devices, +# model, +# network_model, +# ) +# add_to_expression!( +# container, +# ActivePowerRangeExpressionUB, +# ActivePowerVariable, +# devices, +# model, +# network_model, +# ) +# add_feedforward_arguments!(container, model, devices) +# return +# end +# +# function construct_device!( +# container::OptimizationContainer, +# sys::PSY.System, +# ::ModelConstructStage, +# model::DeviceModel{H, D}, +# network_model::NetworkModel{S}, +# ) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} +# devices = +# get_available_components(H, sys, get_attribute(model, "filter_function")) +# +# add_constraints!( +# container, +# ActivePowerVariableLimitsConstraint, +# ActivePowerRangeExpressionLB, +# devices, +# model, +# network_model, +# ) +# add_constraints!( +# container, +# ActivePowerVariableLimitsConstraint, +# ActivePowerRangeExpressionUB, +# devices, +# model, +# network_model, +# ) +# +# add_constraints!( +# container, +# ReactivePowerVariableLimitsConstraint, +# ReactivePowerVariable, +# devices, +# model, +# network_model, +# ) +# +# add_feedforward_constraints!(container, model, devices) +# +# objective_function!(container, devices, model, S) +# +# add_constraint_dual!(container, sys, model) +# return +# end +# +# """ +# Construct model for HydroGen with RunOfRiver Commitment Formulation +# with only Active Power. +# """ +# function construct_device!( +# container::OptimizationContainer, +# sys::PSY.System, +# ::ArgumentConstructStage, +# model::DeviceModel{H, D}, +# network_model::NetworkModel{S}, +# ) where { +# H <: PSY.HydroGen, +# D <: HydroCommitmentRunOfRiver, +# S <: PM.AbstractActivePowerModel, +# } +# devices = +# get_available_components(H, sys, get_attribute(model, "filter_function")) +# +# add_variables!(container, ActivePowerVariable, devices, D()) +# add_variables!(container, OnVariable, devices, D()) +# add_variables!(container, EnergyOutput, devices, D()) +# add_to_expression!( +# container, +# ActivePowerBalance, +# ActivePowerVariable, +# devices, +# model, +# network_model, +# ) +# +# add_expressions!(container, ProductionCostExpression, devices, model) +# +# add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) +# add_to_expression!( +# container, +# ActivePowerRangeExpressionLB, +# ActivePowerVariable, +# devices, +# model, +# network_model, +# ) +# add_to_expression!( +# container, +# ActivePowerRangeExpressionUB, +# ActivePowerVariable, +# devices, +# model, +# network_model, +# ) +# +# add_feedforward_arguments!(container, model, devices) +# return +# end +# +# function construct_device!( +# container::OptimizationContainer, +# sys::PSY.System, +# ::ModelConstructStage, +# model::DeviceModel{H, D}, +# network_model::NetworkModel{S}, +# ) where { +# H <: PSY.HydroGen, +# D <: HydroCommitmentRunOfRiver, +# S <: PM.AbstractActivePowerModel, +# } +# devices = +# get_available_components(H, sys, get_attribute(model, "filter_function")) +# +# add_constraints!( +# container, +# ActivePowerVariableLimitsConstraint, +# ActivePowerRangeExpressionLB, +# devices, +# model, +# network_model, +# ) +# add_constraints!( +# container, +# ActivePowerVariableLimitsConstraint, +# ActivePowerRangeExpressionUB, +# devices, +# model, +# network_model, +# ) +# +# add_feedforward_constraints!(container, model, devices) +# +# objective_function!(container, devices, model, S) +# +# add_constraint_dual!(container, sys, model) +# return +# end diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 95cd47efec..4db297382a 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -1,293 +1,296 @@ -#! format: off -requires_initialization(::AbstractHydroFormulation) = false -requires_initialization(::AbstractHydroUnitCommitment) = true - -get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB - -########################### ActivePowerVariable, HydroGen ################################# -get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 -get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max - -############## ActivePowerVariable, HydroDispatchRunOfRiver #################### -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 - -############## ReactivePowerVariable, HydroGen #################### -get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power(d) -get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).min -get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).max - -############## OnVariable, HydroGen #################### -get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true -get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 - -########################### Parameter related set functions ################################ -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) - -get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min - -#################### Initial Conditions for models ############### -initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) -initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() -initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 -initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) -initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() - -########################Objective Function################################################## -proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 -proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) - -objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE - -sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE -sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE - -variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 -variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) -variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) - -#! format: on - -function get_initial_conditions_device_model( - ::OperationModel, - model::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroEnergyReservoir} - return model -end - -function get_initial_conditions_device_model( - ::OperationModel, - ::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroDispatch} - return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) -end - -function get_default_time_series_names( - ::Type{<:PSY.HydroGen}, - ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - ActivePowerTimeSeriesParameter => "max_active_power", - ReactivePowerTimeSeriesParameter => "max_active_power", - ) -end - -function get_default_attributes( - ::Type{T}, - ::Type{D}, -) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} - return Dict{String, Any}("reservation" => false) -end - -""" -Time series constraints -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:RangeConstraintLBExpressions}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -""" -Add semicontinuous range constraints for Hydro Unit Commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -""" -Min and max reactive Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ReactivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_reactive_power_limits(x) -end - -""" -Min and max active Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_active_power_limits(x) -end - -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchRunOfRiver}, -) - return (min = 0.0, max = PSY.get_max_active_power(x)) -end - -""" -Add power variable limits constraints for hydro unit commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -""" -Add power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroGen, - W <: AbstractHydroDispatchFormulation, - X <: PM.AbstractPowerModel, -} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -##################################### Auxillary Variables ############################ -function _calculate_aux_variable_value!( - container::OptimizationContainer, - ::AuxVarKey{EnergyOutput, T}, - system::PSY.System, - p_variable_results::JuMPVariableArray, -) where {T <: PSY.HydroGen} - devices = axes(p_variable_results, 1) - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - aux_variable_container = get_aux_variable(container, EnergyOutput(), T) - for name in devices, t in time_steps - aux_variable_container[name, t] = - jump_value(p_variable_results[name, t]) * fraction_of_hour - end - - return -end - -function calculate_aux_variable_value!( - container::OptimizationContainer, - aux_key::AuxVarKey{EnergyOutput, T}, - system::PSY.System, -) where {T <: PSY.HydroGen} - p_variable_results = get_variable(container, ActivePowerVariable(), T) - _calculate_aux_variable_value!( - container, - aux_key, - system, - p_variable_results, - ) - return -end - -##################################### Hydro generation cost ############################ -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, OnVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - return -end +# #! format: off +# requires_initialization(::AbstractHydroFormulation) = false +# requires_initialization(::AbstractHydroUnitCommitment) = true +# +# #DELETE +# # get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 +# get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB +# get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB +# +# ########################### ActivePowerVariable, HydroGen ################################# +# get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false +# get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) +# get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min +# get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 +# get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max +# +# ############## ActivePowerVariable, HydroDispatchRunOfRiver #################### +# get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 +# +# ############## ReactivePowerVariable, HydroGen #################### +# get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false +# get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power(d) +# get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).min +# get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).max +# +# ############## OnVariable, HydroGen #################### +# get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true +# get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 +# +# ########################### Parameter related set functions ################################ +# get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) +# get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) +# +# get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 +# get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 +# get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max +# get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min +# +# #################### Initial Conditions for models ############### +# initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) +# initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() +# initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) +# initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() +# initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 +# initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() +# initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) +# initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() +# +# ########################Objective Function################################################## +# proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 +# proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) +# +# objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +# objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +# objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE +# +# sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE +# sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE +# +# variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 +# variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) +# variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) +# +# #! format: on +# +# function get_initial_conditions_device_model( +# ::OperationModel, +# model::DeviceModel{T, <:AbstractHydroFormulation}, +# ) where {T <: PSY.HydroEnergyReservoir} +# return model +# end +# +# function get_initial_conditions_device_model( +# ::OperationModel, +# ::DeviceModel{T, <:AbstractHydroFormulation}, +# ) where {T <: PSY.HydroDispatch} +# return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) +# end +# +# # DELETE +# # function get_default_time_series_names( +# # ::Type{<:PSY.HydroGen}, +# # ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, +# # ) +# # return Dict{Type{<:TimeSeriesParameter}, String}( +# # ActivePowerTimeSeriesParameter => "max_active_power", +# # ReactivePowerTimeSeriesParameter => "max_active_power", +# # ) +# # end +# +# # DELETE +# # function get_default_attributes( +# # ::Type{T}, +# # ::Type{D}, +# # ) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} +# # return Dict{String, Any}("reservation" => false) +# # end +# +# """ +# Time series constraints +# """ +# function add_constraints!( +# container::OptimizationContainer, +# T::Type{ActivePowerVariableLimitsConstraint}, +# U::Type{<:Union{VariableType, ExpressionType}}, +# devices::IS.FlattenIteratorWrapper{V}, +# model::DeviceModel{V, W}, +# ::NetworkModel{X}, +# ) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} +# if !has_semicontinuous_feedforward(model, U) +# add_range_constraints!(container, T, U, devices, model, X) +# end +# add_parameterized_upper_bound_range_constraints( +# container, +# ActivePowerVariableTimeSeriesLimitsConstraint, +# U, +# ActivePowerTimeSeriesParameter, +# devices, +# model, +# X, +# ) +# return +# end +# +# function add_constraints!( +# container::OptimizationContainer, +# T::Type{ActivePowerVariableLimitsConstraint}, +# U::Type{<:RangeConstraintLBExpressions}, +# devices::IS.FlattenIteratorWrapper{V}, +# model::DeviceModel{V, W}, +# ::NetworkModel{X}, +# ) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} +# if !has_semicontinuous_feedforward(model, U) +# add_range_constraints!(container, T, U, devices, model, X) +# end +# return +# end +# +# """ +# Add semicontinuous range constraints for Hydro Unit Commitment formulation +# """ +# function add_constraints!( +# container::OptimizationContainer, +# T::Type{ActivePowerVariableLimitsConstraint}, +# U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, +# devices::IS.FlattenIteratorWrapper{V}, +# model::DeviceModel{V, W}, +# ::NetworkModel{X}, +# ) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} +# add_semicontinuous_range_constraints!(container, T, U, devices, model, X) +# return +# end +# +# function add_constraints!( +# container::OptimizationContainer, +# T::Type{ActivePowerVariableLimitsConstraint}, +# U::Type{<:Union{VariableType, ExpressionType}}, +# devices::IS.FlattenIteratorWrapper{V}, +# model::DeviceModel{V, W}, +# ::NetworkModel{X}, +# ) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} +# add_semicontinuous_range_constraints!(container, T, U, devices, model, X) +# add_parameterized_upper_bound_range_constraints( +# container, +# ActivePowerVariableTimeSeriesLimitsConstraint, +# U, +# ActivePowerTimeSeriesParameter, +# devices, +# model, +# X, +# ) +# return +# end +# +# """ +# Min and max reactive Power Variable limits +# """ +# function get_min_max_limits( +# x::PSY.HydroGen, +# ::Type{<:ReactivePowerVariableLimitsConstraint}, +# ::Type{<:AbstractHydroFormulation}, +# ) +# return PSY.get_reactive_power_limits(x) +# end +# +# """ +# Min and max active Power Variable limits +# """ +# function get_min_max_limits( +# x::PSY.HydroGen, +# ::Type{<:ActivePowerVariableLimitsConstraint}, +# ::Type{<:AbstractHydroFormulation}, +# ) +# return PSY.get_active_power_limits(x) +# end +# +# function get_min_max_limits( +# x::PSY.HydroGen, +# ::Type{<:ActivePowerVariableLimitsConstraint}, +# ::Type{HydroDispatchRunOfRiver}, +# ) +# return (min = 0.0, max = PSY.get_max_active_power(x)) +# end +# +# """ +# Add power variable limits constraints for hydro unit commitment formulation +# """ +# function add_constraints!( +# container::OptimizationContainer, +# T::Type{<:PowerVariableLimitsConstraint}, +# U::Type{<:Union{VariableType, ExpressionType}}, +# devices::IS.FlattenIteratorWrapper{V}, +# model::DeviceModel{V, W}, +# ::NetworkModel{X}, +# ) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} +# add_semicontinuous_range_constraints!(container, T, U, devices, model, X) +# return +# end +# +# """ +# Add power variable limits constraints for hydro dispatch formulation +# """ +# function add_constraints!( +# container::OptimizationContainer, +# T::Type{<:PowerVariableLimitsConstraint}, +# U::Type{<:Union{VariableType, ExpressionType}}, +# devices::IS.FlattenIteratorWrapper{V}, +# model::DeviceModel{V, W}, +# ::NetworkModel{X}, +# ) where { +# V <: PSY.HydroGen, +# W <: AbstractHydroDispatchFormulation, +# X <: PM.AbstractPowerModel, +# } +# if !has_semicontinuous_feedforward(model, U) +# add_range_constraints!(container, T, U, devices, model, X) +# end +# return +# end +# +# ##################################### Auxillary Variables ############################ +# function _calculate_aux_variable_value!( +# container::OptimizationContainer, +# ::AuxVarKey{EnergyOutput, T}, +# system::PSY.System, +# p_variable_results::JuMPVariableArray, +# ) where {T <: PSY.HydroGen} +# devices = axes(p_variable_results, 1) +# time_steps = get_time_steps(container) +# resolution = get_resolution(container) +# fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR +# aux_variable_container = get_aux_variable(container, EnergyOutput(), T) +# for name in devices, t in time_steps +# aux_variable_container[name, t] = +# jump_value(p_variable_results[name, t]) * fraction_of_hour +# end +# +# return +# end +# +# function calculate_aux_variable_value!( +# container::OptimizationContainer, +# aux_key::AuxVarKey{EnergyOutput, T}, +# system::PSY.System, +# ) where {T <: PSY.HydroGen} +# p_variable_results = get_variable(container, ActivePowerVariable(), T) +# _calculate_aux_variable_value!( +# container, +# aux_key, +# system, +# p_variable_results, +# ) +# return +# end +# +# ##################################### Hydro generation cost ############################ +# function objective_function!( +# container::OptimizationContainer, +# devices::IS.FlattenIteratorWrapper{T}, +# ::DeviceModel{T, U}, +# ::Type{<:PM.AbstractPowerModel}, +# ) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} +# add_variable_cost!(container, ActivePowerVariable(), devices, U()) +# add_proportional_cost!(container, OnVariable(), devices, U()) +# return +# end +# +# function objective_function!( +# container::OptimizationContainer, +# devices::IS.FlattenIteratorWrapper{T}, +# ::DeviceModel{T, U}, +# ::Type{<:PM.AbstractPowerModel}, +# ) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} +# add_variable_cost!(container, ActivePowerVariable(), devices, U()) +# return +# end diff --git a/test/test_device_hydro_generation_constructors.jl b/test/test_device_hydro_generation_constructors.jl deleted file mode 100644 index 7545c57ace..0000000000 --- a/test/test_device_hydro_generation_constructors.jl +++ /dev/null @@ -1,121 +0,0 @@ -################################### -###### FIXED OUTPUT TESTS ######### -################################### - -@testset "Hydro DCPLossLess FixedOutput" begin - device_model = DeviceModel(HydroDispatch, FixedOutput) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with FixedOutput formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, FixedOutput) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -### RUN OF RIVER DISPATCH TESTS ### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -#### RUN OF RIVER COMMIT TESTS #### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end From f2ad9b464d19b64c8c13c29f379eec6b289b8616 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 17 May 2023 15:45:16 -0700 Subject: [PATCH 276/370] add script for debug --- scripts/debug_emulation_psi.jl | 74 ++++++++++++++++++++ src/operation/operation_problem_templates.jl | 2 +- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 scripts/debug_emulation_psi.jl diff --git a/scripts/debug_emulation_psi.jl b/scripts/debug_emulation_psi.jl new file mode 100644 index 0000000000..779169427a --- /dev/null +++ b/scripts/debug_emulation_psi.jl @@ -0,0 +1,74 @@ +using Pkg +Pkg.activate("test") +Pkg.instantiate() +using Revise + + +using PowerSimulations +using PowerSystems +using PowerSystemCaseBuilder +using InfrastructureSystems +const PSY = PowerSystems +const PSI = PowerSimulations +const PSB = PowerSystemCaseBuilder +using Xpress +using JuMP +using Logging +using Dates +using TimeSeries + +c_sys5_reg = PSB.build_system(PSITestSystems, "c_sys5_reg") + +# Transform Deterministic to Static +load_dict = Dict() +for load in get_components(PowerLoad, c_sys5_reg) + name = get_name(load) + t_array = get_time_series_array( + Deterministic, + load, + "max_active_power", + start_time = DateTime("2024-01-01T00:00:00"), + ) + load_dict[name] = collect(values(t_array)) +end + +reg_dict = Dict() +for dev in get_components(RegulationDevice, c_sys5_reg) + name = get_name(dev) + t_array = get_time_series_array( + Deterministic, + dev, + "max_active_power", + start_time = DateTime("2024-01-01T00:00:00"), + ) + reg_dict[name] = collect(values(t_array)) +end + +remove_time_series!(c_sys5_reg, Deterministic) + +resolution = Dates.Hour(1) +dates = range(DateTime("2024-01-01T00:00:00"), step = resolution, length = 24) +c_sys5_reg + +for load in get_components(PowerLoad, c_sys5_reg) + name = get_name(load) + t_array = load_dict[name] + data = TimeArray(dates, t_array) + ts = SingleTimeSeries("max_active_power", data) + add_time_series!(c_sys5_reg, load, ts) +end + +for dev in get_components(RegulationDevice, c_sys5_reg) + name = get_name(dev) + t_array = reg_dict[name] + data = TimeArray(dates, t_array) + ts = SingleTimeSeries("max_active_power", data) + add_time_series!(c_sys5_reg, dev, ts) +end + + +template_agc = template_agc_reserve_deployment() +model = EmulationModel(template_agc, c_sys5_reg; optimizer = Xpress.Optimizer) +build!(model; executions = 24, output_dir = mktempdir(; cleanup = true)) + +run!(model) \ No newline at end of file diff --git a/src/operation/operation_problem_templates.jl b/src/operation/operation_problem_templates.jl index 5a60c03c52..0d714a118c 100644 --- a/src/operation/operation_problem_templates.jl +++ b/src/operation/operation_problem_templates.jl @@ -130,6 +130,6 @@ function template_agc_reserve_deployment(; kwargs...) ReserveLimitedRegulation, ), ) - set_service_model!(template, ServiceModel(PSY.AGC, PIDSmoothACE)) + set_service_model!(template, ServiceModel(PSY.AGC, PIDSmoothACE, "AGC_Area1")) return template end From 546fd79663e89be597ce233dd97e639b775674ff Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 17 May 2023 18:29:27 -0700 Subject: [PATCH 277/370] add debug script --- scripts/debug_emulation_psi.jl | 60 ++++++++++++++++------------------ 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/scripts/debug_emulation_psi.jl b/scripts/debug_emulation_psi.jl index 779169427a..c58dee29b0 100644 --- a/scripts/debug_emulation_psi.jl +++ b/scripts/debug_emulation_psi.jl @@ -3,7 +3,6 @@ Pkg.activate("test") Pkg.instantiate() using Revise - using PowerSimulations using PowerSystems using PowerSystemCaseBuilder @@ -22,53 +21,52 @@ c_sys5_reg = PSB.build_system(PSITestSystems, "c_sys5_reg") # Transform Deterministic to Static load_dict = Dict() for load in get_components(PowerLoad, c_sys5_reg) - name = get_name(load) - t_array = get_time_series_array( - Deterministic, - load, - "max_active_power", - start_time = DateTime("2024-01-01T00:00:00"), - ) - load_dict[name] = collect(values(t_array)) + name = get_name(load) + t_array = get_time_series_array( + Deterministic, + load, + "max_active_power"; + start_time = DateTime("2024-01-01T00:00:00"), + ) + load_dict[name] = collect(values(t_array)) end reg_dict = Dict() for dev in get_components(RegulationDevice, c_sys5_reg) - name = get_name(dev) - t_array = get_time_series_array( - Deterministic, - dev, - "max_active_power", - start_time = DateTime("2024-01-01T00:00:00"), - ) - reg_dict[name] = collect(values(t_array)) + name = get_name(dev) + t_array = get_time_series_array( + Deterministic, + dev, + "max_active_power"; + start_time = DateTime("2024-01-01T00:00:00"), + ) + reg_dict[name] = collect(values(t_array)) end remove_time_series!(c_sys5_reg, Deterministic) resolution = Dates.Hour(1) -dates = range(DateTime("2024-01-01T00:00:00"), step = resolution, length = 24) +dates = range(DateTime("2024-01-01T00:00:00"); step = resolution, length = 24) c_sys5_reg for load in get_components(PowerLoad, c_sys5_reg) - name = get_name(load) - t_array = load_dict[name] - data = TimeArray(dates, t_array) - ts = SingleTimeSeries("max_active_power", data) - add_time_series!(c_sys5_reg, load, ts) + name = get_name(load) + t_array = load_dict[name] + data = TimeArray(dates, t_array) + ts = SingleTimeSeries("max_active_power", data) + add_time_series!(c_sys5_reg, load, ts) end for dev in get_components(RegulationDevice, c_sys5_reg) - name = get_name(dev) - t_array = reg_dict[name] - data = TimeArray(dates, t_array) - ts = SingleTimeSeries("max_active_power", data) - add_time_series!(c_sys5_reg, dev, ts) + name = get_name(dev) + t_array = reg_dict[name] + data = TimeArray(dates, t_array) + ts = SingleTimeSeries("max_active_power", data) + add_time_series!(c_sys5_reg, dev, ts) end - template_agc = template_agc_reserve_deployment() model = EmulationModel(template_agc, c_sys5_reg; optimizer = Xpress.Optimizer) -build!(model; executions = 24, output_dir = mktempdir(; cleanup = true)) +build!(model; executions = 23, output_dir = mktempdir(; cleanup = true)) -run!(model) \ No newline at end of file +run!(model) From b3eef9444ed7199dc44516b93381866006f8b417 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 17 May 2023 18:29:48 -0700 Subject: [PATCH 278/370] update constructor to change some variables to be indexed by AGC --- src/services_models/services_constructor.jl | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index 4955ba66a9..5992bf7b35 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -241,18 +241,18 @@ function construct_service!( if !isempty(setdiff(areas, agc_areas)) throw( IS.ConflictingInputsError( - "All area most have an AGC service assigned in order to model the System's Frequency regulation", + "All area must have an AGC service assigned in order to model the System's Frequency regulation", ), ) end add_variables!(container, SteadyStateFrequencyDeviation) - add_variables!(container, AreaMismatchVariable, areas, T()) - add_variables!(container, SmoothACE, areas, T()) - add_variables!(container, LiftVariable, areas, T()) + add_variables!(container, AreaMismatchVariable, services, T()) + add_variables!(container, SmoothACE, services, T()) + add_variables!(container, LiftVariable, services, T()) add_variables!(container, ActivePowerVariable, areas, T()) - add_variables!(container, DeltaActivePowerUpVariable, areas, T()) - add_variables!(container, DeltaActivePowerDownVariable, areas, T()) + add_variables!(container, DeltaActivePowerUpVariable, services, T()) + add_variables!(container, DeltaActivePowerDownVariable, services, T()) add_variables!(container, AdditionalDeltaActivePowerUpVariable, areas, T()) add_variables!(container, AdditionalDeltaActivePowerDownVariable, areas, T()) @@ -291,12 +291,12 @@ function construct_service!( areas = PSY.get_components(PSY.Area, sys) services = get_available_components(S, sys) - add_constraints!(container, AbsoluteValueConstraint, LiftVariable, areas, model) + add_constraints!(container, AbsoluteValueConstraint, LiftVariable, services, model) add_constraints!( container, FrequencyResponseConstraint, SteadyStateFrequencyDeviation, - areas, + services, model, sys, ) @@ -304,17 +304,17 @@ function construct_service!( container, SACEPIDAreaConstraint, SteadyStateFrequencyDeviation, - areas, + services, model, sys, ) - add_constraints!(container, BalanceAuxConstraint, SmoothACE, areas, model, sys) + add_constraints!(container, BalanceAuxConstraint, SmoothACE, services, model, sys) add_feedforward_constraints!(container, model, services) add_constraint_dual!(container, sys, model) - objective_function!(container, areas, model) + objective_function!(container, services, model) return end From 19b34b2cf49cad09ef35cbc458d2ccb8fc496b25 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 17 May 2023 18:30:02 -0700 Subject: [PATCH 279/370] add name to default template --- src/operation/operation_problem_templates.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operation/operation_problem_templates.jl b/src/operation/operation_problem_templates.jl index 0d714a118c..5a60c03c52 100644 --- a/src/operation/operation_problem_templates.jl +++ b/src/operation/operation_problem_templates.jl @@ -130,6 +130,6 @@ function template_agc_reserve_deployment(; kwargs...) ReserveLimitedRegulation, ), ) - set_service_model!(template, ServiceModel(PSY.AGC, PIDSmoothACE, "AGC_Area1")) + set_service_model!(template, ServiceModel(PSY.AGC, PIDSmoothACE)) return template end From 5abf243084f65a6c9bbe1a6f83aab50a29d8b799 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 17 May 2023 18:30:42 -0700 Subject: [PATCH 280/370] update objective function to dispatch per AGC --- src/devices_models/devices/common/objective_functions.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices_models/devices/common/objective_functions.jl b/src/devices_models/devices/common/objective_functions.jl index 52b56a17eb..c5b5655136 100644 --- a/src/devices_models/devices/common/objective_functions.jl +++ b/src/devices_models/devices/common/objective_functions.jl @@ -100,9 +100,9 @@ end function add_proportional_cost!( container::OptimizationContainer, ::U, - areas::IS.FlattenIteratorWrapper{T}, + agcs::IS.FlattenIteratorWrapper{T}, ::PIDSmoothACE, -) where {T <: PSY.Area, U <: LiftVariable} +) where {T <: PSY.AGC, U <: LiftVariable} lift_variable = get_variable(container, U(), T) for index in Iterators.product(axes(lift_variable)...) add_to_objective_invariant_expression!( From c456aae25e8a69ca1e7f401479363fab3cd06d3b Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 17 May 2023 18:31:00 -0700 Subject: [PATCH 281/370] update expression to dispatch per agc --- src/devices_models/devices/common/add_to_expression.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/devices_models/devices/common/add_to_expression.jl b/src/devices_models/devices/common/add_to_expression.jl index 9ba446b447..10b70dc188 100644 --- a/src/devices_models/devices/common/add_to_expression.jl +++ b/src/devices_models/devices/common/add_to_expression.jl @@ -1050,15 +1050,15 @@ function add_to_expression!( V <: PSY.AGC, W <: AbstractServiceFormulation, } - names = [PSY.get_name(PSY.get_area(s)) for s in services] + names = PSY.get_name.(services) time_steps = get_time_steps(container) if !has_container_key(container, T, V) - expression = add_expression_container!(container, T(), PSY.Area, names, time_steps) + expression = add_expression_container!(container, T(), PSY.AGC, names, time_steps) end - expression = get_expression(container, T(), PSY.Area) - variable = get_variable(container, U(), PSY.Area) + expression = get_expression(container, T(), PSY.AGC) + variable = get_variable(container, U(), PSY.AGC) for s in services, t in time_steps - name = PSY.get_name(PSY.get_area(s)) + name = PSY.get_name(s) _add_to_jump_expression!( expression[name, t], variable[t], From 81a64192fcf6f9efb5cd04a73d5c7a6d8199ab1d Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 17 May 2023 18:33:28 -0700 Subject: [PATCH 282/370] update reg device to dispatch using both area and agc --- src/devices_models/devices/regulation_device.jl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/devices_models/devices/regulation_device.jl b/src/devices_models/devices/regulation_device.jl index e8aa37ed72..aba9df5a68 100644 --- a/src/devices_models/devices/regulation_device.jl +++ b/src/devices_models/devices/regulation_device.jl @@ -180,8 +180,8 @@ function add_constraints!( R_dn = get_variable(container, DeltaActivePowerDownVariable(), T) R_up_emergency = get_variable(container, AdditionalDeltaActivePowerUpVariable(), T) R_dn_emergency = get_variable(container, AdditionalDeltaActivePowerUpVariable(), T) - area_reserve_up = get_variable(container, DeltaActivePowerUpVariable(), PSY.Area) - area_reserve_dn = get_variable(container, DeltaActivePowerDownVariable(), PSY.Area) + area_reserve_up = get_variable(container, DeltaActivePowerUpVariable(), PSY.AGC) + area_reserve_dn = get_variable(container, DeltaActivePowerDownVariable(), PSY.AGC) component_names = [PSY.get_name(d) for d in devices] participation_assignment_up = add_constraints_container!( @@ -208,9 +208,11 @@ function add_constraints!( services = PSY.get_services(d) if length(services) > 1 device_agc = (a for a in PSY.get_services(d) if isa(a, PSY.AGC)) + agc_name = PSY.get_name.(device_agc)[1] area_name = PSY.get_name.(PSY.get_area.(device_agc))[1] else device_agc = first(services) + agc_name = PSY.get_name(device_agc) area_name = PSY.get_name(PSY.get_area(device_agc)) end p_factor = PSY.get_participation_factor(d) @@ -218,12 +220,12 @@ function add_constraints!( participation_assignment_up[name, t] = JuMP.@constraint( container.JuMPmodel, R_up[name, t] == - (p_factor.up * area_reserve_up[area_name, t]) + R_up_emergency[name, t] + (p_factor.up * area_reserve_up[agc_name, t]) + R_up_emergency[name, t] ) participation_assignment_dn[name, t] = JuMP.@constraint( container.JuMPmodel, R_dn[name, t] == - (p_factor.dn * area_reserve_dn[area_name, t]) + R_dn_emergency[name, t] + (p_factor.dn * area_reserve_dn[agc_name, t]) + R_dn_emergency[name, t] ) JuMP.add_to_expression!(expr_up[area_name, t], -1 * R_up_emergency[name, t]) JuMP.add_to_expression!(expr_dn[area_name, t], -1 * R_dn_emergency[name, t]) From e0200415591e75abf50c3fe1d0e592ab96ffde0e Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 17 May 2023 18:33:36 -0700 Subject: [PATCH 283/370] update agc device model --- src/services_models/agc.jl | 118 ++++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 54 deletions(-) diff --git a/src/services_models/agc.jl b/src/services_models/agc.jl index 3ad04e7799..ebd2e578b4 100644 --- a/src/services_models/agc.jl +++ b/src/services_models/agc.jl @@ -1,25 +1,25 @@ #! format: off -get_variable_multiplier(_, ::Type{<:PSY.Area}, ::AbstractAGCFormulation) = NaN -########################## ActivePowerVariable, Area ########################### +get_variable_multiplier(_, ::Type{<:PSY.AGC}, ::AbstractAGCFormulation) = NaN +########################## ActivePowerVariable, AGC ########################### ########################## SteadyStateFrequencyDeviation ################################## -get_variable_binary(::SteadyStateFrequencyDeviation, ::Type{<:PSY.Area}, ::AbstractAGCFormulation) = false +get_variable_binary(::SteadyStateFrequencyDeviation, ::Type{<:PSY.AGC}, ::AbstractAGCFormulation) = false get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.Area}, ::AbstractAGCFormulation) = false - ########################## SmoothACE, AggregationTopology ########################### get_variable_binary(::SmoothACE, ::Type{<:PSY.AggregationTopology}, ::AbstractAGCFormulation) = false +get_variable_binary(::SmoothACE, ::Type{<:PSY.AGC}, ::AbstractAGCFormulation) = false -########################## DeltaActivePowerUpVariable, Area ########################### +########################## DeltaActivePowerUpVariable, AGC ########################### -get_variable_binary(::DeltaActivePowerUpVariable, ::Type{<:PSY.Area}, ::AbstractAGCFormulation) = false -get_variable_lower_bound(::DeltaActivePowerUpVariable, ::PSY.Area, ::AbstractAGCFormulation) = 0.0 +get_variable_binary(::DeltaActivePowerUpVariable, ::Type{<:PSY.AGC}, ::AbstractAGCFormulation) = false +get_variable_lower_bound(::DeltaActivePowerUpVariable, ::PSY.AGC, ::AbstractAGCFormulation) = 0.0 -########################## DeltaActivePowerDownVariable, Area ########################### +########################## DeltaActivePowerDownVariable, AGC ########################### -get_variable_binary(::DeltaActivePowerDownVariable, ::Type{<:PSY.Area}, ::AbstractAGCFormulation) = false -get_variable_lower_bound(::DeltaActivePowerDownVariable, ::PSY.Area, ::AbstractAGCFormulation) = 0.0 +get_variable_binary(::DeltaActivePowerDownVariable, ::Type{<:PSY.AGC}, ::AbstractAGCFormulation) = false +get_variable_lower_bound(::DeltaActivePowerDownVariable, ::PSY.AGC, ::AbstractAGCFormulation) = 0.0 ########################## AdditionalDeltaPowerUpVariable, Area ########################### @@ -31,12 +31,12 @@ get_variable_lower_bound(::AdditionalDeltaActivePowerUpVariable, ::PSY.Area, ::A get_variable_binary(::AdditionalDeltaActivePowerDownVariable, ::Type{<:PSY.Area}, ::AbstractAGCFormulation) = false get_variable_lower_bound(::AdditionalDeltaActivePowerDownVariable, ::PSY.Area, ::AbstractAGCFormulation) = 0.0 -########################## AreaMismatchVariable, Area ########################### -get_variable_binary(::AreaMismatchVariable, ::Type{<:PSY.Area}, ::AbstractAGCFormulation) = false +########################## AreaMismatchVariable, AGC ########################### +get_variable_binary(::AreaMismatchVariable, ::Type{<:PSY.AGC}, ::AbstractAGCFormulation) = false ########################## LiftVariable, Area ########################### -get_variable_binary(::LiftVariable, ::Type{<:PSY.Area}, ::AbstractAGCFormulation) = false -get_variable_lower_bound(::LiftVariable, ::PSY.Area, ::AbstractAGCFormulation) = 0.0 +get_variable_binary(::LiftVariable, ::Type{<:PSY.AGC}, ::AbstractAGCFormulation) = false +get_variable_lower_bound(::LiftVariable, ::PSY.AGC, ::AbstractAGCFormulation) = 0.0 initial_condition_default(::AreaControlError, d::PSY.AGC, ::AbstractAGCFormulation) = PSY.get_initial_ace(d) initial_condition_variable(::AreaControlError, d::PSY.AGC, ::AbstractAGCFormulation) = AreaMismatchVariable() @@ -67,7 +67,7 @@ function add_variables!( ::Type{T}, ) where {T <: SteadyStateFrequencyDeviation} time_steps = get_time_steps(container) - variable = add_variable_container!(container, T(), PSY.Area, time_steps) + variable = add_variable_container!(container, T(), PSY.AGC, time_steps) for t in time_steps variable[t] = JuMP.@variable(container.JuMPmodel, base_name = "ΔF_{$(t)}") end @@ -88,20 +88,20 @@ function add_constraints!( container::OptimizationContainer, ::Type{T}, ::Type{LiftVariable}, - areas::IS.FlattenIteratorWrapper{U}, + agcs::IS.FlattenIteratorWrapper{U}, ::ServiceModel{PSY.AGC, V}, -) where {T <: AbsoluteValueConstraint, U <: PSY.Area, V <: PIDSmoothACE} +) where {T <: AbsoluteValueConstraint, U <: PSY.AGC, V <: PIDSmoothACE} time_steps = get_time_steps(container) - area_names = PSY.get_name.(areas) + agc_names = PSY.get_name.(agcs) container_lb = - add_constraints_container!(container, T(), U, area_names, time_steps; meta = "lb") + add_constraints_container!(container, T(), U, agc_names, time_steps; meta = "lb") container_ub = - add_constraints_container!(container, T(), U, area_names, time_steps; meta = "ub") + add_constraints_container!(container, T(), U, agc_names, time_steps; meta = "ub") mismatch = get_variable(container, AreaMismatchVariable(), U) z = get_variable(container, LiftVariable(), U) jump_model = get_jump_model(container) - for t in time_steps, a in area_names + for t in time_steps, a in agc_names container_lb[a, t] = JuMP.@constraint(jump_model, mismatch[a, t] <= z[a, t]) container_ub[a, t] = JuMP.@constraint(jump_model, -1 * mismatch[a, t] <= z[a, t]) end @@ -116,15 +116,16 @@ function add_constraints!( container::OptimizationContainer, ::Type{T}, ::Type{SteadyStateFrequencyDeviation}, - areas::IS.FlattenIteratorWrapper{U}, + agcs::IS.FlattenIteratorWrapper{U}, ::ServiceModel{PSY.AGC, V}, sys::PSY.System, -) where {T <: FrequencyResponseConstraint, U <: PSY.Area, V <: PIDSmoothACE} +) where {T <: FrequencyResponseConstraint, U <: PSY.AGC, V <: PIDSmoothACE} time_steps = get_time_steps(container) - area_names = PSY.get_name.(areas) + agc_names = PSY.get_name.(agcs) frequency_response = 0.0 - for area in PSY.get_components(PSY.Area, sys) + for agc in PSY.get_components(x -> x.available, PSY.AGC, sys) + area = PSY.get_area(agc) frequency_response += PSY.get_load_response(area) end @@ -139,22 +140,26 @@ function add_constraints!( # This value is the one updated later in simulation based on the UC result inv_frequency_reponse = 1 / frequency_response - area_balance = get_variable(container, ActivePowerVariable(), U) + area_balance = get_variable(container, ActivePowerVariable(), PSY.Area) frequency = get_variable(container, SteadyStateFrequencyDeviation(), U) R_up = get_variable(container, DeltaActivePowerUpVariable(), U) R_dn = get_variable(container, DeltaActivePowerDownVariable(), U) - R_up_emergency = get_variable(container, AdditionalDeltaActivePowerUpVariable(), U) - R_dn_emergency = get_variable(container, AdditionalDeltaActivePowerUpVariable(), U) + R_up_emergency = + get_variable(container, AdditionalDeltaActivePowerUpVariable(), PSY.Area) + R_dn_emergency = + get_variable(container, AdditionalDeltaActivePowerUpVariable(), PSY.Area) const_container = add_constraints_container!(container, T(), PSY.System, time_steps) for t in time_steps system_balance = sum(area_balance.data[:, t]) - for a in area_names + for agc in agcs + a = PSY.get_name(agc) + area_name = PSY.get_name(PSY.get_area(agc)) JuMP.add_to_expression!(system_balance, R_up[a, t]) JuMP.add_to_expression!(system_balance, -1 * R_dn[a, t]) - JuMP.add_to_expression!(system_balance, R_up_emergency[a, t]) - JuMP.add_to_expression!(system_balance, -1 * R_dn_emergency[a, t]) + JuMP.add_to_expression!(system_balance, R_up_emergency[area_name, t]) + JuMP.add_to_expression!(system_balance, -1 * R_dn_emergency[area_name, t]) end const_container[t] = JuMP.@constraint( container.JuMPmodel, @@ -168,12 +173,13 @@ function add_constraints!( container::OptimizationContainer, ::Type{T}, ::Type{SteadyStateFrequencyDeviation}, - areas::IS.FlattenIteratorWrapper{U}, + agcs::IS.FlattenIteratorWrapper{U}, ::ServiceModel{PSY.AGC, V}, sys::PSY.System, -) where {T <: SACEPIDAreaConstraint, U <: PSY.Area, V <: PIDSmoothACE} +) where {T <: SACEPIDAreaConstraint, U <: PSY.AGC, V <: PIDSmoothACE} services = get_available_components(PSY.AGC, sys) time_steps = get_time_steps(container) + agc_names = PSY.get_name.(services) area_names = [PSY.get_name(PSY.get_area(s)) for s in services] RAW_ACE = get_expression(container, RawACE(), U) SACE = get_variable(container, SmoothACE(), U) @@ -181,7 +187,7 @@ function add_constraints!( container, SACEPIDAreaConstraint(), U, - area_names, + agc_names, time_steps, ) @@ -191,7 +197,7 @@ function add_constraints!( ki = PSY.get_K_i(service) kd = PSY.get_K_d(service) Δt = convert(Dates.Second, container.resolution).value - a = PSY.get_name(PSY.get_area(service)) + a = PSY.get_name(service) for t in time_steps if t == 1 ACE_ini = get_initial_condition(container, AreaControlError(), PSY.AGC)[ix] @@ -217,46 +223,50 @@ function add_constraints!( container::OptimizationContainer, ::Type{T}, ::Type{SmoothACE}, - areas::IS.FlattenIteratorWrapper{U}, + agcs::IS.FlattenIteratorWrapper{U}, ::ServiceModel{PSY.AGC, V}, sys::PSY.System, -) where {T <: BalanceAuxConstraint, U <: PSY.Area, V <: PIDSmoothACE} +) where {T <: BalanceAuxConstraint, U <: PSY.AGC, V <: PIDSmoothACE} time_steps = get_time_steps(container) - area_names = PSY.get_name.(areas) + agc_names = PSY.get_name.(agcs) aux_equation = add_constraints_container!( container, BalanceAuxConstraint(), PSY.System, - area_names, + agc_names, time_steps, ) - area_mismatch = get_variable(container, AreaMismatchVariable(), PSY.Area) - SACE = get_variable(container, SmoothACE(), PSY.Area) - R_up = get_variable(container, DeltaActivePowerUpVariable(), PSY.Area) - R_dn = get_variable(container, DeltaActivePowerDownVariable(), PSY.Area) + area_mismatch = get_variable(container, AreaMismatchVariable(), PSY.AGC) + SACE = get_variable(container, SmoothACE(), PSY.AGC) + R_up = get_variable(container, DeltaActivePowerUpVariable(), PSY.AGC) + R_dn = get_variable(container, DeltaActivePowerDownVariable(), PSY.AGC) R_up_emergency = get_variable(container, AdditionalDeltaActivePowerUpVariable(), PSY.Area) R_dn_emergency = get_variable(container, AdditionalDeltaActivePowerUpVariable(), PSY.Area) - for t in time_steps, a in area_names - aux_equation[a, t] = JuMP.@constraint( - container.JuMPmodel, - -1 * SACE[a, t] == - (R_up[a, t] - R_dn[a, t]) + - (R_up_emergency[a, t] - R_dn_emergency[a, t]) + - area_mismatch[a, t] - ) + for t in time_steps + for agc in agcs + a = PSY.get_name(agc) + area_name = PSY.get_name(PSY.get_area(agc)) + aux_equation[a, t] = JuMP.@constraint( + container.JuMPmodel, + -1 * SACE[a, t] == + (R_up[a, t] - R_dn[a, t]) + + (R_up_emergency[area_name, t] - R_dn_emergency[area_name, t]) + + area_mismatch[a, t] + ) + end end return end function objective_function!( container::OptimizationContainer, - areas::IS.FlattenIteratorWrapper{T}, + agcs::IS.FlattenIteratorWrapper{T}, ::ServiceModel{<:PSY.AGC, U}, -) where {T <: PSY.Area, U <: PIDSmoothACE} - add_proportional_cost!(container, LiftVariable(), areas, U()) +) where {T <: PSY.AGC, U <: PIDSmoothACE} + add_proportional_cost!(container, LiftVariable(), agcs, U()) return end From 8400588c653c6bb46f48fecd96d7b955cce73f58 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 19 May 2023 17:01:30 -0700 Subject: [PATCH 284/370] update agc model --- src/services_models/agc.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services_models/agc.jl b/src/services_models/agc.jl index ebd2e578b4..96a47b2590 100644 --- a/src/services_models/agc.jl +++ b/src/services_models/agc.jl @@ -124,7 +124,7 @@ function add_constraints!( agc_names = PSY.get_name.(agcs) frequency_response = 0.0 - for agc in PSY.get_components(x -> x.available, PSY.AGC, sys) + for agc in agcs area = PSY.get_area(agc) frequency_response += PSY.get_load_response(area) end From 75ec415f1cfe1e811ff2369d0ce5b36067a260c5 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Fri, 19 May 2023 17:01:39 -0700 Subject: [PATCH 285/370] update rts --- scripts/create_rts_systems.jl | 376 ++++++++++++++++++++++++++++++++ scripts/rts_simulation_setup.jl | 155 +++++++++++++ scripts/script_utils.jl | 73 +++++++ scripts/test_emulation_psi.jl | 72 ++++++ 4 files changed, 676 insertions(+) create mode 100644 scripts/create_rts_systems.jl create mode 100644 scripts/rts_simulation_setup.jl create mode 100644 scripts/script_utils.jl create mode 100644 scripts/test_emulation_psi.jl diff --git a/scripts/create_rts_systems.jl b/scripts/create_rts_systems.jl new file mode 100644 index 0000000000..ae4d33d819 --- /dev/null +++ b/scripts/create_rts_systems.jl @@ -0,0 +1,376 @@ +using Pkg +Pkg.activate("test") +Pkg.instantiate() +using Revise + +using PowerSimulations +using PowerSystems +using PowerSystemCaseBuilder +using InfrastructureSystems +const PSY = PowerSystems +const PSI = PowerSimulations +const PSB = PowerSystemCaseBuilder +using Xpress +using JuMP +using Logging +using Dates +using TimeSeries +using Random +rng = MersenneTwister(1234) +using Interpolations +using Distributions + +sys_DA = PSB.build_RTS_GMLC_DA_sys_noTS(; raw_data = PSB.RTS_DIR) +sys_RT = PSB.build_RTS_GMLC_RT_sys_noTS(; raw_data = PSB.RTS_DIR) +sys_RT_HourAhead = PSB.build_RTS_GMLC_RT_sys_noTS(; raw_data = PSB.RTS_DIR) + +reserve_hydro = true # use false to remove hydro from the reserve provision devices + +area_maps_regup = Dict() +area_maps_regup["1"] = "Reg_Up_R1" +area_maps_regup["2"] = "Reg_Up_R2" +area_maps_regup["3"] = "Reg_Up_R3" + +area_maps_regdn = Dict() +area_maps_regdn["1"] = "Reg_Down_R1" +area_maps_regdn["2"] = "Reg_Down_R2" +area_maps_regdn["3"] = "Reg_Down_R3" + +area_maps_spin = Dict() +area_maps_spin["1"] = "Spin_Up_R1" +area_maps_spin["2"] = "Spin_Up_R2" +area_maps_spin["3"] = "Spin_Up_R3" + +for sys in [sys_DA, sys_RT, sys_RT_HourAhead] + # Adjust Reserve Provisions + # Remove Flex Reserves + res_up = get_component(VariableReserve{ReserveUp}, sys, "Flex_Up") + if !isnothing(res_up) + remove_component!(sys, res_up) + end + res_dn = get_component(VariableReserve{ReserveDown}, sys, "Flex_Down") + if !isnothing(res_dn) + remove_component!(sys, res_dn) + end + mult = 1.0 + # Reg Up Split + reg_reserve_up = get_component(VariableReserve, sys, "Reg_Up") + set_requirement!(reg_reserve_up, mult * get_requirement(reg_reserve_up)) + for name in ["Reg_Up_R1", "Reg_Up_R2", "Reg_Up_R3"] + reg_zone = PSY.VariableReserve{ReserveUp}(; + name = name, + available = true, + time_frame = reg_reserve_up.time_frame, + requirement = reg_reserve_up.requirement / 3.0, + ) + old_ts = get_time_series(SingleTimeSeries, reg_reserve_up, "requirement") + add_component!(sys, reg_zone) + add_time_series!(sys, reg_zone, old_ts) + end + remove_component!(sys, reg_reserve_up) + # Reg Down Split + reg_reserve_dn = get_component(VariableReserve, sys, "Reg_Down") + set_requirement!(reg_reserve_dn, mult * get_requirement(reg_reserve_dn)) + for name in ["Reg_Down_R1", "Reg_Down_R2", "Reg_Down_R3"] + reg_zone = PSY.VariableReserve{ReserveDown}(; + name = name, + available = true, + time_frame = reg_reserve_dn.time_frame, + requirement = reg_reserve_dn.requirement / 3.0, + ) + old_ts = get_time_series(SingleTimeSeries, reg_reserve_dn, "requirement") + add_component!(sys, reg_zone) + add_time_series!(sys, reg_zone, old_ts) + end + remove_component!(sys, reg_reserve_dn) + + spin_reserve_R1 = get_component(VariableReserve, sys, "Spin_Up_R1") + spin_reserve_R2 = get_component(VariableReserve, sys, "Spin_Up_R2") + spin_reserve_R3 = get_component(VariableReserve, sys, "Spin_Up_R3") + + for g in get_components(Generator, sys) + clear_services!(g) + end + # Remove Destillate Fuel from sys and update services + for g in get_components( + x -> x.prime_mover in [PrimeMovers.CT, PrimeMovers.CC], + ThermalStandard, + sys, + ) + if get_fuel(g) == ThermalFuels.DISTILLATE_FUEL_OIL + remove_component!(sys, g) + continue + end + g.operation_cost.shut_down = g.operation_cost.start_up / 2.0 + + #= + # Small generators do not participate in reg + if PSY.get_base_power(g) > 3.0 + clear_services!(g) + add_service!(g, reg_reserve_dn) + add_service!(g, reg_reserve_up) + continue + end + =# + area_name = get_name(get_area(get_bus(g))) + reg_up = get_component(VariableReserve, sys, area_maps_regup[area_name]) + reg_dn = get_component(VariableReserve, sys, area_maps_regdn[area_name]) + add_service!(g, reg_up, sys) + add_service!(g, reg_dn, sys) + + # Update costs to avoid degenerate solutions in thermal + if get_prime_mover(g) == PrimeMovers.CT + set_status!(g, false) + set_active_power!(g, 0.0) + old_pwl_array = get_variable(get_operation_cost(g)) |> get_cost + new_pwl_array = similar(old_pwl_array) + for (ix, tup) in enumerate(old_pwl_array) + if ix ∈ [1, length(old_pwl_array)] + cost_noise = 50.0 * rand() + new_pwl_array[ix] = ((tup[1] + cost_noise), tup[2]) + else + try_again = true + while try_again + cost_noise = 50.0 * rand() + power_noise = 0.01 * rand() + slope_previous = + ((tup[1] + cost_noise) - old_pwl_array[ix - 1][1]) / + ((tup[2] - power_noise) - old_pwl_array[ix - 1][2]) + slope_next = + (-(tup[1] + cost_noise) + old_pwl_array[ix + 1][1]) / + (-(tup[2] - power_noise) + old_pwl_array[ix + 1][2]) + new_pwl_array[ix] = ((tup[1] + cost_noise), (tup[2] - power_noise)) + try_again = slope_previous > slope_next + end + end + end + get_variable(get_operation_cost(g)).cost = new_pwl_array + end + end + + for g in get_components( + x -> !(x.prime_mover in [PrimeMovers.CT, PrimeMovers.CC]), + ThermalStandard, + sys, + ) + get_operation_cost(g).shut_down = get_operation_cost(g).start_up / 2.0 + area_name = get_name(get_area(get_bus(g))) + reg_up = get_component(VariableReserve, sys, area_maps_regup[area_name]) + reg_dn = get_component(VariableReserve, sys, area_maps_regdn[area_name]) + reg_spin = get_component(VariableReserve, sys, area_maps_spin[area_name]) + if !(get_fuel(g) == ThermalFuels.NUCLEAR) + add_service!(g, reg_up, sys) + add_service!(g, reg_dn, sys) + add_service!(g, reg_spin, sys) + end + end + + #= + for g in get_components(RenewableDispatch, sys) + set_operation_cost!(g, TwoPartCost(0.0, 0.0)) + area_name = get_name(get_area(get_bus(g))) + reg_up = get_component(VariableReserve, sys, area_maps_regup[area_name]) + reg_dn = get_component(VariableReserve, sys, area_maps_regdn[area_name]) + reg_spin = get_component(VariableReserve, sys, area_maps_spin[area_name]) + add_service!(g, reg_up, sys) + add_service!(g, reg_dn, sys) + add_service!(g, reg_spin, sys) + end + =# + + for g in get_components(HydroEnergyReservoir, sys) + area_name = get_name(get_area(get_bus(g))) + reg_up = get_component(VariableReserve, sys, area_maps_regup[area_name]) + reg_dn = get_component(VariableReserve, sys, area_maps_regdn[area_name]) + reg_spin = get_component(VariableReserve, sys, area_maps_spin[area_name]) + add_service!(g, reg_up, sys) + add_service!(g, reg_dn, sys) + add_service!(g, reg_spin, sys) + end + + #Remove units that make no sense to include + names = [ + "114_SYNC_COND_1", + "314_SYNC_COND_1", + "313_STORAGE_1", + "214_SYNC_COND_1", + "212_CSP_1", + ] + for d in get_components(x -> x.name ∈ names, Generator, sys) + remove_component!(sys, d) + end + for br in get_components(DCBranch, sys) + remove_component!(sys, br) + end + for d in get_components(Storage, sys) + remove_component!(sys, d) + end + + # Update Ramp Limits + for d in + get_components(x -> (occursin(r"STEAM|NUCLEAR", get_name(x))), ThermalStandard, sys) + + #get_fuel(d) == ThermalFuels.COAL && set_ramp_limits!(d, (up = 0.001, down = 0.001)) + + #if get_rating(d) < 3.0 + # set_status!(d, false) + # clear_services!(d) + #reserve_hydro && add_service!(d, reg_reserve_up) + #reserve_hydro && add_service!(d, reg_reserve_dn) + #add_service!(d, spin_reserve_R1, sys) + # set_active_power!(d, 0.0) + # continue + #end + get_operation_cost(d).shut_down = get_operation_cost(d).start_up / 2.0 + if get_fuel(d) == ThermalFuels.NUCLEAR + set_ramp_limits!(d, (up = 0.0, down = 0.0)) + set_time_limits!(d, (up = 4380.0, down = 4380.0)) + end + end + + # Remove bad Hydro + for d in get_components(HydroDispatch, sys) + remove_component!(sys, d) + end + + #= + for area in get_components(Area, sys) + if get_name(area) == "1" + continue + end + remove_component!(sys, area) + end + for b in get_components(Bus, sys) + set_area!(b, get_component(Area, sys, "1")) + end + =# +end + +horizon_DA = 48 +interval_DA = Hour(24) +horizon_RT = 24 +interval_RT = Minute(5) +horizon_HourAhead = 24 +interval_HourAhead = Hour(1) + +transform_single_time_series!(sys_DA, horizon_DA, interval_DA) +transform_single_time_series!(sys_RT, horizon_RT, interval_RT) +transform_single_time_series!(sys_RT_HourAhead, horizon_HourAhead, interval_HourAhead) + +to_json(sys_DA, "data/sys_DA_1h.json"; force = true) +to_json(sys_RT, "data/sys_RT_5min.json"; force = true) +to_json(sys_RT_HourAhead, "data/sys_RT_HourAhead_2hours.json"; force = true) + +########################################################################################## +################################## Here AGC code starts ################################## +########################################################################################## + +sys_AGC = deepcopy(sys_RT) +remove_time_series!(sys_AGC, DeterministicSingleTimeSeries) +remove_time_series!(sys_AGC, SingleTimeSeries) + +init_time = DateTime("2020-01-01T00:00:00") +final_time = DateTime("2020-12-31T23:59:56") +end_time = DateTime("2020-12-31T23:55:00") + +for type in [RenewableFix, ElectricLoad] + for d in get_components(type, sys_RT) + @show get_name(d) + for l in get_time_series_names(SingleTimeSeries, d) + step_time = Minute(5) + step_range = Int(Minute(5) / Second(4)) + _dates = range(init_time, final_time; step = Second(4)) + time_series = get_time_series(SingleTimeSeries, d, l) + total_interp_timeseries = Vector{Float64}(undef, size(_dates)[1]) + current_date = init_time + i = 0 + while current_date < end_time + t_stamps = range(current_date; step = Second(4), length = step_range) + val_init = values(time_series[current_date].data)[1] + val_next = values(time_series[current_date + step_time].data)[1] + _vals = range(1, 2; length = step_range) + interp_vals = LinearInterpolation(1:2, [val_init, val_next])(_vals) + if type <: ElectricLoad + noise = rand(Normal(0.0, 0.025), step_range) + else + noise = rand(Normal(0.0, 0.1), step_range) + end + interp_vals .+= noise + total_interp_timeseries[(i * step_range + 1):((i + 1) * step_range)] = + interp_vals + current_date += step_time + i = i + 1 + end + data = TimeArray(_dates, max.(total_interp_timeseries, 0.0)) + ts = SingleTimeSeries(l, data) + c = get_component(typeof(d), sys_AGC, get_name(d)) + add_time_series!(sys_AGC, c, ts) + end + end +end + +#= +for g in get_components(ThermalStandard, sys_AGC) + _date = DateTime("2020-09-01") + step_time = Hour(1) + current_date = deepcopy(_date) + while current_date < DateTime("2020-09-11") + t_stamps = range(current_date, step = Second(4), length = 900) + vals = zeros(length(t_stamps)) + forecast = Deterministic("get_rating", TimeArray(t_stamps, vals)) + add_forecast!(sys_AGC, g, forecast) + current_date += step_time + end +end + +for g in get_components(RenewableDispatch, sys_AGC) + _date = DateTime("2020-09-01") + step_time = Hour(1) + current_date = deepcopy(_date) + while current_date < DateTime("2020-09-11") + t_stamps = range(current_date, step = Second(4), length = 900) + vals = zeros(length(t_stamps)) + forecast = Deterministic("get_rating", TimeArray(t_stamps, vals)) + add_forecast!(sys_AGC, g, forecast) + current_date += step_time + end +end +=# + +for area in get_components(Area, sys_AGC) + AGC_service = PSY.AGC(; + name = "AGC_Area_$(area)", + available = true, + bias = 739.0, + K_p = 2.5 + rand(Normal(0.0, 0.025), 1)[1], + K_i = max(0.1 + rand(Normal(0.0, 0.00025), 1)[1], 0.001), + K_d = 0.0, + delta_t = 4, + area = get_component(Area, sys_AGC, get_name(area)), + ) + + contributing_devices = Vector{PSY.Device}() + reg_reserve_up = + get_component(VariableReserve, sys_AGC, area_maps_regup[get_name(area)]) + for g in get_components(x -> x.bus.area == area, Generator, sys_AGC) + if has_service(g, reg_reserve_up) + droop = if isa(g, ThermalStandard) + 0.04 * PSY.get_base_power(g) + else + 0.05 * PSY.get_base_power(g) + end + p_factor = (up = 1.0, dn = 1.0) + t = RegulationDevice(g; participation_factor = p_factor, droop = droop) + add_component!(sys_AGC, t) + push!(contributing_devices, t) + end + end + + add_service!(sys_AGC, AGC_service, contributing_devices) +end + +for res in get_components(VariableReserve, sys_AGC) + remove_component!(sys_AGC, res) +end + +to_json(sys_AGC, "data/sys_AGC_4sec.json"; force = true) diff --git a/scripts/rts_simulation_setup.jl b/scripts/rts_simulation_setup.jl new file mode 100644 index 0000000000..c56efda8c7 --- /dev/null +++ b/scripts/rts_simulation_setup.jl @@ -0,0 +1,155 @@ +using Pkg +Pkg.activate("test") +Pkg.instantiate() +using Revise + +using PowerSimulations +using PowerSystems +using PowerSystemCaseBuilder +using InfrastructureSystems +const PSY = PowerSystems +const PSI = PowerSimulations +const PSB = PowerSystemCaseBuilder +using Xpress +using JuMP +using Logging +using Dates +using TimeSeries + +include("script_utils.jl") + +sys_DA = System("data/sys_DA_1h.json") +sys_RT = System("data/sys_RT_5min.json") + +mipgap = 1e-2 # 1% +num_steps = 30 +starttime = DateTime("2020-01-01T00:00:00") + +template_uc = get_uc_ptdf_template(sys_DA) +set_device_model!(template_uc, ThermalStandard, ThermalBasicUnitCommitment) +template_ed = get_ed_ptdf_template(sys_RT) +set_device_model!(template_ed, ThermalStandard, ThermalBasicDispatch) + +models = SimulationModels(; + decision_models = [ + DecisionModel( + template_uc, + sys_DA; + name = "UC", + optimizer = optimizer_with_attributes(Xpress.Optimizer, "MIPRELSTOP" => mipgap), + system_to_file = false, + initialize_model = true, + optimizer_solve_log_print = false, + direct_mode_optimizer = true, + rebuild_model = false, + store_variable_names = true, + calculate_conflict = true, + ), + DecisionModel( + template_ed, + sys_RT; + name = "ED", + optimizer = optimizer_with_attributes(Xpress.Optimizer, "MIPRELSTOP" => mipgap), + system_to_file = false, + initialize_model = true, + optimizer_solve_log_print = false, + direct_mode_optimizer = true, + rebuild_model = false, + store_variable_names = true, + calculate_conflict = true, + ), + ], +) + +# Set-up the sequence UC-ED +sequence = SimulationSequence(; + models = models, + feedforwards = Dict( + "ED" => [ + SemiContinuousFeedforward(; + component_type = ThermalStandard, + source = OnVariable, + affected_values = [ActivePowerVariable], + ), + FixValueFeedforward(; + component_type = VariableReserve{ReserveUp}, + source = ActivePowerReserveVariable, + affected_values = [ActivePowerReserveVariable], + ), + FixValueFeedforward(; + component_type = VariableReserve{ReserveDown}, + source = ActivePowerReserveVariable, + affected_values = [ActivePowerReserveVariable], + ), + ], + ), + ini_cond_chronology = InterProblemChronology(), +) + +sim = Simulation(; + name = "compact_sim", + steps = num_steps, + models = models, + sequence = sequence, + initial_time = starttime, + simulation_folder = mktempdir(; cleanup = true), +) + +build!(sim; console_level = Logging.Info, serialize = false) +execute!(sim; enable_progress_bar = true); + +uc = sim.models.decision_models[1] +ed = sim.models.decision_models[2] +vars = ed.internal.container.variables +pwl = vars[PSI.VariableKey{PSI.PieceWiseLinearCostVariable, ThermalStandard}("")] +pwl_var = pwl["315_STEAM_1", 1, 1] +p = vars[PSI.VariableKey{ActivePowerVariable, ThermalStandard}("")] +p["315_STEAM_1", 1] +p_stuff = p["315_STEAM_1", :] +p_vals = value.(p_stuff) +value.(regup["324_PV_3", :]) + +param = ed.internal.container.parameters +on_val = param[PSI.ParameterKey{OnStatusParameter, ThermalStandard}("")].parameter_array +regup3 = + param[PSI.ParameterKey{FixValueParameter, VariableReserve{ReserveUp}}( + "Reg_Up_R3", + )].parameter_array +spinup3 = + param[PSI.ParameterKey{FixValueParameter, VariableReserve{ReserveUp}}( + "Spin_Up_R3", + )].parameter_array +regdown3 = + param[PSI.ParameterKey{FixValueParameter, VariableReserve{ReserveDown}}( + "Reg_Down_R3", + )].parameter_array +regup3["315_STEAM_1", :] +regdown3["315_STEAM_1", :] +spinup3["315_STEAM_1", :] +on_val_steam = JuMP.fix_value.(on_val["315_STEAM_1", :]) + +g = get_component(ThermalStandard, sys_RT, "315_STEAM_1") +g.bus + +var_state = sim.internal.simulation_state.decision_states.variables +on_state = var_state[PSI.VariableKey{OnVariable, ThermalStandard}("")] +regup_state3 = + var_state[PSI.VariableKey{ActivePowerReserveVariable, VariableReserve{ReserveDown}}( + "Reg_Down_R3", + )] +reg_val = regup_state3.values[!, "315_STEAM_1"] + +constr = ed.internal.container.constraints +ub_ff = constr[PSI.ConstraintKey{FeedforwardSemiContinousConstraint, ThermalStandard}( + "ActivePowerVariable_ub", +)] +ub_ff["315_STEAM_1", :] + +#= +Name Type Sense Bound +R3217 row LE .0000000:00:00 +C4 column LO .000000 +C1598 column UP .000000 +C10643 column LO 1.000000 +C11317 column LO 1.000000 +=# diff --git a/scripts/script_utils.jl b/scripts/script_utils.jl new file mode 100644 index 0000000000..91220bddfb --- /dev/null +++ b/scripts/script_utils.jl @@ -0,0 +1,73 @@ +############################### +###### Model Templates ######## +############################### + +# Some models are commented for RTS model + +function set_uc_models!(template_uc) + set_device_model!(template_uc, ThermalStandard, ThermalStandardUnitCommitment) + set_device_model!(template_uc, RenewableDispatch, RenewableFullDispatch) + set_device_model!(template_uc, RenewableFix, FixedOutput) + set_device_model!(template_uc, PowerLoad, StaticPowerLoad) + set_device_model!(template_uc, TapTransformer, StaticBranchUnbounded) + set_device_model!(template_uc, HydroEnergyReservoir, HydroDispatchRunOfRiver) + set_service_model!( + template_uc, + ServiceModel(VariableReserve{ReserveUp}, RangeReserve; use_slacks = true), + ) + set_service_model!( + template_uc, + ServiceModel(VariableReserve{ReserveDown}, RangeReserve; use_slacks = true), + ) + return +end + +############################### +###### Get Templates ########## +############################### + +### PTDF Bounded #### + +function get_uc_ptdf_template(sys) + template_uc = ProblemTemplate( + NetworkModel( + StandardPTDFModel; + use_slacks = false, + PTDF_matrix = PTDF(sys), + duals = [CopperPlateBalanceConstraint], + ), + ) + set_uc_models!(template_uc) + set_device_model!(template_uc, Line, StaticBranch) + return template_uc +end + +function get_ed_ptdf_template(sys) + template_ed = ProblemTemplate( + NetworkModel( + StandardPTDFModel; + use_slacks = true, + PTDF_matrix = PTDF(sys), + duals = [CopperPlateBalanceConstraint], + ), + ) + set_uc_models!(template_ed) + set_device_model!(template_ed, ThermalStandard, ThermalStandardDispatch) + return template_ed +end + +#### PTDF Unbounded #### + +function get_uc_ptdf_unbounded_template(sys) + template_uc = get_uc_ptdf_template(sys) + set_device_model!(template_uc, Line, StaticBranchUnbounded) + return template_uc +end + +function get_ed_ptdf_unbounded_template(sys_rts_rt) + template_ed = get_ed_ptdf_template(sys_rts_rt) + set_device_model!(template_uc, Line, StaticBranchUnbounded) + return template_ed +end + +####### Simulations ##### diff --git a/scripts/test_emulation_psi.jl b/scripts/test_emulation_psi.jl new file mode 100644 index 0000000000..c58dee29b0 --- /dev/null +++ b/scripts/test_emulation_psi.jl @@ -0,0 +1,72 @@ +using Pkg +Pkg.activate("test") +Pkg.instantiate() +using Revise + +using PowerSimulations +using PowerSystems +using PowerSystemCaseBuilder +using InfrastructureSystems +const PSY = PowerSystems +const PSI = PowerSimulations +const PSB = PowerSystemCaseBuilder +using Xpress +using JuMP +using Logging +using Dates +using TimeSeries + +c_sys5_reg = PSB.build_system(PSITestSystems, "c_sys5_reg") + +# Transform Deterministic to Static +load_dict = Dict() +for load in get_components(PowerLoad, c_sys5_reg) + name = get_name(load) + t_array = get_time_series_array( + Deterministic, + load, + "max_active_power"; + start_time = DateTime("2024-01-01T00:00:00"), + ) + load_dict[name] = collect(values(t_array)) +end + +reg_dict = Dict() +for dev in get_components(RegulationDevice, c_sys5_reg) + name = get_name(dev) + t_array = get_time_series_array( + Deterministic, + dev, + "max_active_power"; + start_time = DateTime("2024-01-01T00:00:00"), + ) + reg_dict[name] = collect(values(t_array)) +end + +remove_time_series!(c_sys5_reg, Deterministic) + +resolution = Dates.Hour(1) +dates = range(DateTime("2024-01-01T00:00:00"); step = resolution, length = 24) +c_sys5_reg + +for load in get_components(PowerLoad, c_sys5_reg) + name = get_name(load) + t_array = load_dict[name] + data = TimeArray(dates, t_array) + ts = SingleTimeSeries("max_active_power", data) + add_time_series!(c_sys5_reg, load, ts) +end + +for dev in get_components(RegulationDevice, c_sys5_reg) + name = get_name(dev) + t_array = reg_dict[name] + data = TimeArray(dates, t_array) + ts = SingleTimeSeries("max_active_power", data) + add_time_series!(c_sys5_reg, dev, ts) +end + +template_agc = template_agc_reserve_deployment() +model = EmulationModel(template_agc, c_sys5_reg; optimizer = Xpress.Optimizer) +build!(model; executions = 23, output_dir = mktempdir(; cleanup = true)) + +run!(model) From bca7b73c46f6a397f632c62583fb76d1ea559a0e Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 23 May 2023 18:32:24 -0700 Subject: [PATCH 286/370] add scripts --- scripts/create_rts_systems.jl | 2 ++ scripts/rts_simulation_setup.jl | 21 ++++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/scripts/create_rts_systems.jl b/scripts/create_rts_systems.jl index ae4d33d819..3466df006f 100644 --- a/scripts/create_rts_systems.jl +++ b/scripts/create_rts_systems.jl @@ -178,6 +178,7 @@ for sys in [sys_DA, sys_RT, sys_RT_HourAhead] end =# + #= for g in get_components(HydroEnergyReservoir, sys) area_name = get_name(get_area(get_bus(g))) reg_up = get_component(VariableReserve, sys, area_maps_regup[area_name]) @@ -187,6 +188,7 @@ for sys in [sys_DA, sys_RT, sys_RT_HourAhead] add_service!(g, reg_dn, sys) add_service!(g, reg_spin, sys) end + =# #Remove units that make no sense to include names = [ diff --git a/scripts/rts_simulation_setup.jl b/scripts/rts_simulation_setup.jl index c56efda8c7..8a1075d81b 100644 --- a/scripts/rts_simulation_setup.jl +++ b/scripts/rts_simulation_setup.jl @@ -15,6 +15,7 @@ using JuMP using Logging using Dates using TimeSeries +using PlotlyJS include("script_utils.jl") @@ -22,7 +23,7 @@ sys_DA = System("data/sys_DA_1h.json") sys_RT = System("data/sys_RT_5min.json") mipgap = 1e-2 # 1% -num_steps = 30 +num_steps = 2 starttime = DateTime("2020-01-01T00:00:00") template_uc = get_uc_ptdf_template(sys_DA) @@ -98,6 +99,22 @@ sim = Simulation(; build!(sim; console_level = Logging.Info, serialize = false) execute!(sim; enable_progress_bar = true); +results_nrb = SimulationResults(sim; ignore_status = true) +results_uc_nrb = get_decision_problem_results(results_nrb, "UC") +results_ed_nrb = get_decision_problem_results(results_nrb, "ED") + +regup_uc = read_realized_variable(results_uc_nrb, "ActivePowerReserveVariable__VariableReserve__ReserveUp__Reg_Up_R1") +dates_uc = regup_uc[!, "DateTime"] +regup_uc_st4 = regup_uc[!, "123_STEAM_2"] + +regup_ed = read_realized_parameter(results_ed_nrb, "FixValueParameter__VariableReserve__ReserveUp__Reg_Up_R1") +dates_ed = regup_ed[!, "DateTime"] +regup_ed_st4 = regup_ed[!, "123_STEAM_2"] +regup_ed_var = read_realized_variable(results_ed_nrb, "ActivePowerReserveVariable__VariableReserve__ReserveUp__Reg_Up_R1") +regup_ed_var_st4 = regup_ed_var[!, "123_STEAM_2"] + +PlotlyJS.plot([PlotlyJS.scatter(x = dates_uc, y = regup_uc_st4 , name = "UC", line_shape = "hv"), PlotlyJS.scatter(x= dates_ed, y = regup_ed_st4 .* 100.0, name = "ED", line_shape = "hv"), PlotlyJS.scatter(x= dates_ed, y = regup_ed_var_st4, name = "ED Var", line_shape = "hv")]) + uc = sim.models.decision_models[1] ed = sim.models.decision_models[2] vars = ed.internal.container.variables @@ -153,3 +170,5 @@ C1598 column UP .000000 C10643 column LO 1.000000 C11317 column LO 1.000000 =# + +# ActivePowerVariable_ThermalStandard_{322_CT_6, 1} - 0.55 _[1465] + ActivePowerReserveVariable_VariableReserve{ReserveUp}_Reg_Up_R3_{322_CT_6, 1} - x[322_CT_6,1] ≤ 0.0 \ No newline at end of file From 55427c787fca201f1939e328f9a2b524deb7c2ca Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Tue, 23 May 2023 18:33:05 -0700 Subject: [PATCH 287/370] Fix service models feedforwards Co-authored-by: jdlara --- src/parameters/add_parameters.jl | 40 +++++++++++++++++++++++++++++ src/parameters/update_parameters.jl | 1 + src/services_models/reserves.jl | 2 +- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index 0c03ce4547..aa1a3df0fa 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -34,6 +34,7 @@ function add_parameters!( return end +#= function add_parameters!( container::OptimizationContainer, ::Type{T}, @@ -53,6 +54,7 @@ function add_parameters!( _add_parameters!(container, T(), source_key, model, devices) return end +=# function add_parameters!( container::OptimizationContainer, @@ -107,6 +109,27 @@ function add_parameters!( return end +function add_parameters!( + container::OptimizationContainer, + ::Type{T}, + ff::FixValueFeedforward, + model::ServiceModel{K, W}, + devices::V, +) where { + T <: VariableValueParameter, + V <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, + W <: AbstractServiceFormulation, + K <: PSY.Reserve, +} where {D <: PSY.Component} + if get_rebuild_model(get_settings(container)) && has_container_key(container, T, D) + return + end + source_key = get_optimization_container_key(ff) + _add_parameters!(container, T(), source_key, model, devices) + _set_affected_variables!(container, T(), K, ff) + return +end + function _set_affected_variables!( container::OptimizationContainer, ::T, @@ -125,6 +148,23 @@ function _set_affected_variables!( return end +function _set_affected_variables!( + container::OptimizationContainer, + ::T, + device_type::Type{U}, + ff::FixValueFeedforward, +) where { + T <: VariableValueParameter, + U <: PSY.Service, +} + meta = ff.optimization_container_key.meta + parameter_container = get_parameter(container, T(), U, meta) + param_attributes = get_attributes(parameter_container) + affected_variables = get_affected_values(ff) + push!(param_attributes.affected_keys, affected_variables...) + return +end + function _add_parameters!( container::OptimizationContainer, param::T, diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index d951a9c1b8..800ff88ebc 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -531,6 +531,7 @@ function _fix_parameter_value!( parameter_attributes::VariableValueAttributes, ) affected_variable_keys = parameter_attributes.affected_keys + @assert !isempty(affected_variable_keys) for var_key in affected_variable_keys variable = get_variable(container, var_key) component_names, time = axes(parameter_array) diff --git a/src/services_models/reserves.jl b/src/services_models/reserves.jl index 5b54896495..309376ecb9 100644 --- a/src/services_models/reserves.jl +++ b/src/services_models/reserves.jl @@ -27,7 +27,7 @@ get_multiplier_value(::RequirementTimeSeriesParameter, d::PSY.Reserve, ::Abstrac get_multiplier_value(::RequirementTimeSeriesParameter, d::PSY.ReserveNonSpinning, ::AbstractReservesFormulation) = PSY.get_requirement(d) get_parameter_multiplier(::VariableValueParameter, d::Type{<:PSY.AbstractReserve}, ::AbstractReservesFormulation) = 1.0 -get_initial_parameter_value(::VariableValueParameter, d::Type{<:PSY.AbstractReserve}, ::AbstractReservesFormulation) = 1.0 +get_initial_parameter_value(::VariableValueParameter, d::Type{<:PSY.AbstractReserve}, ::AbstractReservesFormulation) = 0.0 objective_function_multiplier(::ServiceRequirementVariable, ::StepwiseCostReserve) = 1.0 sos_status(::PSY.ReserveDemandCurve, ::StepwiseCostReserve)=SOSStatusVariable.NO_VARIABLE From d00b08977a7da5ed14c8a5bf4b51d9b8e1e2aa42 Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Wed, 24 May 2023 16:24:03 -0700 Subject: [PATCH 288/370] formatter --- scripts/rts_simulation_setup.jl | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/scripts/rts_simulation_setup.jl b/scripts/rts_simulation_setup.jl index 8a1075d81b..bc71853963 100644 --- a/scripts/rts_simulation_setup.jl +++ b/scripts/rts_simulation_setup.jl @@ -103,17 +103,40 @@ results_nrb = SimulationResults(sim; ignore_status = true) results_uc_nrb = get_decision_problem_results(results_nrb, "UC") results_ed_nrb = get_decision_problem_results(results_nrb, "ED") -regup_uc = read_realized_variable(results_uc_nrb, "ActivePowerReserveVariable__VariableReserve__ReserveUp__Reg_Up_R1") +regup_uc = read_realized_variable( + results_uc_nrb, + "ActivePowerReserveVariable__VariableReserve__ReserveUp__Reg_Up_R1", +) dates_uc = regup_uc[!, "DateTime"] regup_uc_st4 = regup_uc[!, "123_STEAM_2"] -regup_ed = read_realized_parameter(results_ed_nrb, "FixValueParameter__VariableReserve__ReserveUp__Reg_Up_R1") +regup_ed = read_realized_parameter( + results_ed_nrb, + "FixValueParameter__VariableReserve__ReserveUp__Reg_Up_R1", +) dates_ed = regup_ed[!, "DateTime"] regup_ed_st4 = regup_ed[!, "123_STEAM_2"] -regup_ed_var = read_realized_variable(results_ed_nrb, "ActivePowerReserveVariable__VariableReserve__ReserveUp__Reg_Up_R1") +regup_ed_var = read_realized_variable( + results_ed_nrb, + "ActivePowerReserveVariable__VariableReserve__ReserveUp__Reg_Up_R1", +) regup_ed_var_st4 = regup_ed_var[!, "123_STEAM_2"] -PlotlyJS.plot([PlotlyJS.scatter(x = dates_uc, y = regup_uc_st4 , name = "UC", line_shape = "hv"), PlotlyJS.scatter(x= dates_ed, y = regup_ed_st4 .* 100.0, name = "ED", line_shape = "hv"), PlotlyJS.scatter(x= dates_ed, y = regup_ed_var_st4, name = "ED Var", line_shape = "hv")]) +PlotlyJS.plot([ + PlotlyJS.scatter(; x = dates_uc, y = regup_uc_st4, name = "UC", line_shape = "hv"), + PlotlyJS.scatter(; + x = dates_ed, + y = regup_ed_st4 .* 100.0, + name = "ED", + line_shape = "hv", + ), + PlotlyJS.scatter(; + x = dates_ed, + y = regup_ed_var_st4, + name = "ED Var", + line_shape = "hv", + ), +]) uc = sim.models.decision_models[1] ed = sim.models.decision_models[2] @@ -171,4 +194,4 @@ C10643 column LO 1.000000 C11317 column LO 1.000000 =# -# ActivePowerVariable_ThermalStandard_{322_CT_6, 1} - 0.55 _[1465] + ActivePowerReserveVariable_VariableReserve{ReserveUp}_Reg_Up_R3_{322_CT_6, 1} - x[322_CT_6,1] ≤ 0.0 \ No newline at end of file +# ActivePowerVariable_ThermalStandard_{322_CT_6, 1} - 0.55 _[1465] + ActivePowerReserveVariable_VariableReserve{ReserveUp}_Reg_Up_R3_{322_CT_6, 1} - x[322_CT_6,1] ≤ 0.0 From d528a45051d9003c9e9b23e92480af2cd4f15596 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 29 Aug 2023 15:56:37 -0600 Subject: [PATCH 289/370] add missing methods --- src/parameters/add_parameters.jl | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/parameters/add_parameters.jl b/src/parameters/add_parameters.jl index aa1a3df0fa..f2f9060532 100644 --- a/src/parameters/add_parameters.jl +++ b/src/parameters/add_parameters.jl @@ -34,11 +34,10 @@ function add_parameters!( return end -#= function add_parameters!( container::OptimizationContainer, ::Type{T}, - ff::AbstractAffectFeedforward, + ff::LowerBoundFeedforward, model::ServiceModel{S, W}, devices::V, ) where { @@ -54,7 +53,6 @@ function add_parameters!( _add_parameters!(container, T(), source_key, model, devices) return end -=# function add_parameters!( container::OptimizationContainer, From 2c3b8573a2e2f30ebe60a9a5640c92d5e713075c Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 29 Aug 2023 15:59:10 -0600 Subject: [PATCH 290/370] add slacks to some feedforwards --- src/feedforward/feedforwards.jl | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/feedforward/feedforwards.jl b/src/feedforward/feedforwards.jl index 934445d925..e23d2a1c59 100644 --- a/src/feedforward/feedforwards.jl +++ b/src/feedforward/feedforwards.jl @@ -54,10 +54,12 @@ Adds an upper bound constraint to a variable. struct UpperBoundFeedforward <: AbstractAffectFeedforward optimization_container_key::OptimizationContainerKey affected_values::Vector + add_slacks::Bool function UpperBoundFeedforward(; component_type::Type{<:PSY.Component}, source::Type{T}, - affected_values::Vector{DataType}, + affected_values::Vector{DataType}; + add_slacks::Bool = false, meta = CONTAINER_KEY_EMPTY_META, ) where {T} values_vector = Vector(undef, length(affected_values)) @@ -71,7 +73,7 @@ struct UpperBoundFeedforward <: AbstractAffectFeedforward ) end end - new(get_optimization_container_key(T(), component_type, meta), values_vector) + new(get_optimization_container_key(T(), component_type, meta), values_vector, add_slacks) end end @@ -84,10 +86,12 @@ Adds a lower bound constraint to a variable. struct LowerBoundFeedforward <: AbstractAffectFeedforward optimization_container_key::OptimizationContainerKey affected_values::Vector{<:OptimizationContainerKey} + add_slacks::Bool function LowerBoundFeedforward(; component_type::Type{<:PSY.Component}, source::Type{T}, - affected_values::Vector{DataType}, + affected_values::Vector{DataType}; + add_slacks::Bool = false, meta = CONTAINER_KEY_EMPTY_META, ) where {T} values_vector = Vector{VariableKey}(undef, length(affected_values)) @@ -101,7 +105,7 @@ struct LowerBoundFeedforward <: AbstractAffectFeedforward ) end end - new(get_optimization_container_key(T(), component_type, meta), values_vector) + new(get_optimization_container_key(T(), component_type, meta), values_vector, add_slacks) end end @@ -117,7 +121,7 @@ struct SemiContinuousFeedforward <: AbstractAffectFeedforward function SemiContinuousFeedforward(; component_type::Type{<:PSY.Component}, source::Type{T}, - affected_values::Vector{DataType}, + affected_values::Vector{DataType}; meta = CONTAINER_KEY_EMPTY_META, ) where {T} values_vector = Vector{VariableKey}(undef, length(affected_values)) @@ -173,7 +177,7 @@ struct EnergyLimitFeedforward <: AbstractAffectFeedforward component_type::Type{<:PSY.Component}, source::Type{T}, affected_values::Vector{DataType}, - number_of_periods::Int, + number_of_periods::Int; meta = CONTAINER_KEY_EMPTY_META, ) where {T} values_vector = Vector{VariableKey}(undef, length(affected_values)) @@ -209,7 +213,7 @@ struct FixValueFeedforward <: AbstractAffectFeedforward function FixValueFeedforward(; component_type::Type{<:PSY.Component}, source::Type{T}, - affected_values::Vector{DataType}, + affected_values::Vector{DataType}; meta = CONTAINER_KEY_EMPTY_META, ) where {T} values_vector = Vector(undef, length(affected_values)) @@ -243,7 +247,7 @@ struct EnergyTargetFeedforward <: AbstractAffectFeedforward source::Type{T}, affected_values::Vector{DataType}, target_period::Int, - penalty_cost::Float64, + penalty_cost::Float64; meta = CONTAINER_KEY_EMPTY_META, ) where {T} values_vector = Vector{VariableKey}(undef, length(affected_values)) From 38674842d2db73ae63c6e82f4aad2ae739ca6f02 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 30 Aug 2023 10:26:57 -0600 Subject: [PATCH 291/370] fix incorrect addition of semi colon --- src/feedforward/feedforwards.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/feedforward/feedforwards.jl b/src/feedforward/feedforwards.jl index e23d2a1c59..0b1b456c47 100644 --- a/src/feedforward/feedforwards.jl +++ b/src/feedforward/feedforwards.jl @@ -58,7 +58,7 @@ struct UpperBoundFeedforward <: AbstractAffectFeedforward function UpperBoundFeedforward(; component_type::Type{<:PSY.Component}, source::Type{T}, - affected_values::Vector{DataType}; + affected_values::Vector{DataType}, add_slacks::Bool = false, meta = CONTAINER_KEY_EMPTY_META, ) where {T} @@ -90,7 +90,7 @@ struct LowerBoundFeedforward <: AbstractAffectFeedforward function LowerBoundFeedforward(; component_type::Type{<:PSY.Component}, source::Type{T}, - affected_values::Vector{DataType}; + affected_values::Vector{DataType}, add_slacks::Bool = false, meta = CONTAINER_KEY_EMPTY_META, ) where {T} @@ -121,7 +121,7 @@ struct SemiContinuousFeedforward <: AbstractAffectFeedforward function SemiContinuousFeedforward(; component_type::Type{<:PSY.Component}, source::Type{T}, - affected_values::Vector{DataType}; + affected_values::Vector{DataType}, meta = CONTAINER_KEY_EMPTY_META, ) where {T} values_vector = Vector{VariableKey}(undef, length(affected_values)) @@ -177,7 +177,7 @@ struct EnergyLimitFeedforward <: AbstractAffectFeedforward component_type::Type{<:PSY.Component}, source::Type{T}, affected_values::Vector{DataType}, - number_of_periods::Int; + number_of_periods::Int, meta = CONTAINER_KEY_EMPTY_META, ) where {T} values_vector = Vector{VariableKey}(undef, length(affected_values)) @@ -213,7 +213,7 @@ struct FixValueFeedforward <: AbstractAffectFeedforward function FixValueFeedforward(; component_type::Type{<:PSY.Component}, source::Type{T}, - affected_values::Vector{DataType}; + affected_values::Vector{DataType}, meta = CONTAINER_KEY_EMPTY_META, ) where {T} values_vector = Vector(undef, length(affected_values)) @@ -247,7 +247,7 @@ struct EnergyTargetFeedforward <: AbstractAffectFeedforward source::Type{T}, affected_values::Vector{DataType}, target_period::Int, - penalty_cost::Float64; + penalty_cost::Float64, meta = CONTAINER_KEY_EMPTY_META, ) where {T} values_vector = Vector{VariableKey}(undef, length(affected_values)) From 88e5421d4cd0e37abd1e58e27a017bab9cd39e38 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 30 Aug 2023 10:30:17 -0600 Subject: [PATCH 292/370] formatter --- src/feedforward/feedforwards.jl | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/feedforward/feedforwards.jl b/src/feedforward/feedforwards.jl index 0b1b456c47..01c5c0492f 100644 --- a/src/feedforward/feedforwards.jl +++ b/src/feedforward/feedforwards.jl @@ -73,7 +73,11 @@ struct UpperBoundFeedforward <: AbstractAffectFeedforward ) end end - new(get_optimization_container_key(T(), component_type, meta), values_vector, add_slacks) + new( + get_optimization_container_key(T(), component_type, meta), + values_vector, + add_slacks, + ) end end @@ -105,7 +109,11 @@ struct LowerBoundFeedforward <: AbstractAffectFeedforward ) end end - new(get_optimization_container_key(T(), component_type, meta), values_vector, add_slacks) + new( + get_optimization_container_key(T(), component_type, meta), + values_vector, + add_slacks, + ) end end From 39a80f93864f276e6d49996a1e2557d286c5ef78 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 30 Aug 2023 15:05:39 -0600 Subject: [PATCH 293/370] bump PNM version --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index c14ac8467e..d8922c0089 100644 --- a/Project.toml +++ b/Project.toml @@ -42,7 +42,7 @@ JSON3 = "1" JuMP = "1" MathOptInterface = "1" PowerModels = "~0.19" -PowerNetworkMatrices = "^0.7" +PowerNetworkMatrices = "^0.8" PowerSystems = "^2.3" PrettyTables = "^1.3, 2" ProgressMeter = "^1.5" From ecfad95eff27358ec9ff4d8abd89ec543a780e24 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 31 Aug 2023 11:24:32 -0600 Subject: [PATCH 294/370] some reserves updates --- src/PowerSimulations.jl | 1 - src/services_models/group_reserve.jl | 62 --------------------------- src/services_models/reserve_group.jl | 63 ++++++++++++++++++++++++++++ src/services_models/reserves.jl | 1 - 4 files changed, 63 insertions(+), 64 deletions(-) delete mode 100644 src/services_models/group_reserve.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 2fc2a5b2b6..ca6f9b8000 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -534,7 +534,6 @@ include("services_models/agc.jl") include("services_models/reserves.jl") include("services_models/reserve_group.jl") include("services_models/transmission_interface.jl") -include("services_models/group_reserve.jl") include("services_models/service_slacks.jl") include("services_models/services_constructor.jl") diff --git a/src/services_models/group_reserve.jl b/src/services_models/group_reserve.jl deleted file mode 100644 index 6942e9fba0..0000000000 --- a/src/services_models/group_reserve.jl +++ /dev/null @@ -1,62 +0,0 @@ - -############################### Reserve Variables` ######################################### -""" -This function checks if the variables for reserves were created -""" -function check_activeservice_variables( - container::OptimizationContainer, - contributing_services::Vector{T}, -) where {T <: PSY.Service} - for service in contributing_services - get_variable( - container, - ActivePowerReserveVariable(), - typeof(service), - PSY.get_name(service), - ) - end - return -end - -################################## Reserve Requirement Constraint ########################## -""" -This function creates the requirement constraint that will be attained by the apropriate services -""" -function add_constraints!( - container::OptimizationContainer, - ::Type{RequirementConstraint}, - service::SR, - contributing_services::Vector{<:PSY.Service}, - model::ServiceModel{SR, GroupReserve}, -) where {SR <: PSY.StaticReserveGroup} - time_steps = get_time_steps(container) - service_name = PSY.get_name(service) - add_constraints_container!( - container, - RequirementConstraint(), - SR, - [service_name], - time_steps; - meta = service_name, - ) - constraint = get_constraint(container, RequirementConstraint(), SR, service_name) - use_slacks = get_use_slacks(model) - reserve_variables = [ - get_variable(container, ActivePowerReserveVariable(), typeof(r), PSY.get_name(r)) for r in contributing_services - ] - - requirement = PSY.get_requirement(service) - for t in time_steps - resource_expression = JuMP.GenericAffExpr{Float64, JuMP.VariableRef}() - for reserve_variable in reserve_variables - JuMP.add_to_expression!(resource_expression, sum(reserve_variable[:, t])) - end - if use_slacks - resource_expression += slack_vars[t] - end - constraint[service_name, t] = - JuMP.@constraint(container.JuMPmodel, resource_expression >= requirement) - end - - return -end diff --git a/src/services_models/reserve_group.jl b/src/services_models/reserve_group.jl index b64e1613a7..d4628f977f 100644 --- a/src/services_models/reserve_group.jl +++ b/src/services_models/reserve_group.jl @@ -9,3 +9,66 @@ function get_default_attributes( ::Type{GroupReserve}) where {T <: PSY.ReserveDirection} return Dict{String, Any}() end + + +############################### Reserve Variables` ######################################### +""" +This function checks if the variables for reserves were created +""" +function check_activeservice_variables( + container::OptimizationContainer, + contributing_services::Vector{T}, +) where {T <: PSY.Service} + for service in contributing_services + get_variable( + container, + ActivePowerReserveVariable(), + typeof(service), + PSY.get_name(service), + ) + end + return +end + +################################## Reserve Requirement Constraint ########################## +""" +This function creates the requirement constraint that will be attained by the apropriate services +""" +function add_constraints!( + container::OptimizationContainer, + ::Type{RequirementConstraint}, + service::SR, + contributing_services::Vector{<:PSY.Service}, + model::ServiceModel{SR, GroupReserve}, +) where {SR <: PSY.StaticReserveGroup} + time_steps = get_time_steps(container) + service_name = PSY.get_name(service) + add_constraints_container!( + container, + RequirementConstraint(), + SR, + [service_name], + time_steps; + meta = service_name, + ) + constraint = get_constraint(container, RequirementConstraint(), SR, service_name) + use_slacks = get_use_slacks(model) + reserve_variables = [ + get_variable(container, ActivePowerReserveVariable(), typeof(r), PSY.get_name(r)) for r in contributing_services + ] + + requirement = PSY.get_requirement(service) + for t in time_steps + resource_expression = JuMP.GenericAffExpr{Float64, JuMP.VariableRef}() + for reserve_variable in reserve_variables + JuMP.add_to_expression!(resource_expression, sum(reserve_variable[:, t])) + end + if use_slacks + resource_expression += slack_vars[t] + end + constraint[service_name, t] = + JuMP.@constraint(container.JuMPmodel, resource_expression >= requirement) + end + + return +end diff --git a/src/services_models/reserves.jl b/src/services_models/reserves.jl index 309376ecb9..7a33ef15b9 100644 --- a/src/services_models/reserves.jl +++ b/src/services_models/reserves.jl @@ -16,7 +16,6 @@ get_variable_upper_bound(::ActivePowerReserveVariable, ::PSY.ReserveNonSpinning, get_variable_upper_bound(::ActivePowerReserveVariable, ::PSY.ReserveNonSpinning, d::PSY.Storage, _) = PSY.get_output_active_power_limits(d).max get_variable_lower_bound(::ActivePowerReserveVariable, ::PSY.ReserveNonSpinning, ::PSY.Component, _) = 0.0 - ############################### ServiceRequirementVariable, ReserveDemandCurve ################################ get_variable_binary(::ServiceRequirementVariable, ::Type{<:PSY.ReserveDemandCurve}, ::AbstractReservesFormulation) = false From 7f89f39b3d334f4885f60a720b665b0fbf4dae8a Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 31 Aug 2023 11:24:39 -0600 Subject: [PATCH 295/370] bump PSI --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index d8922c0089..e0a105f6ce 100644 --- a/Project.toml +++ b/Project.toml @@ -43,7 +43,7 @@ JuMP = "1" MathOptInterface = "1" PowerModels = "~0.19" PowerNetworkMatrices = "^0.8" -PowerSystems = "^2.3" +PowerSystems = "^2.6" PrettyTables = "^1.3, 2" ProgressMeter = "^1.5" TimeSeries = "~0.23" From 2c2a1938b384a53ea63b032f007e92ae0e333924 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 31 Aug 2023 11:24:49 -0600 Subject: [PATCH 296/370] add HPS to tests --- test/Project.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/Project.toml b/test/Project.toml index 72c8c475a9..2b72548673 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -7,6 +7,7 @@ DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" GLPK = "60bf3e95-4087-53dc-ae20-288a0d20c6a6" HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b" +HydroPowerSimulations = "fc1677e0-6ad7-4515-bf3a-bd6bf20a0b1b" InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1" Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9" JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" @@ -30,6 +31,6 @@ UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" [compat] HiGHS = "=1.1.2" -julia = "^1.6" -PowerSystemCaseBuilder = "~1.0.2" Ipopt = "=1.4.0" +PowerSystemCaseBuilder = "~1.0.2" +julia = "^1.6" From 1717546bb4ea39e490bb435be6266b5c1b0d6951 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 31 Aug 2023 14:15:08 -0600 Subject: [PATCH 297/370] limit max fraction --- src/services_models/reserves.jl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/services_models/reserves.jl b/src/services_models/reserves.jl index 7a33ef15b9..578a7de7cc 100644 --- a/src/services_models/reserves.jl +++ b/src/services_models/reserves.jl @@ -3,18 +3,18 @@ get_variable_multiplier(_, ::Type{<:PSY.Reserve}, ::AbstractReservesFormulation) = NaN ############################### ActivePowerReserveVariable, Reserve ######################################### - get_variable_binary(::ActivePowerReserveVariable, ::Type{<:PSY.Reserve}, ::AbstractReservesFormulation) = false -get_variable_upper_bound(::ActivePowerReserveVariable, ::PSY.Reserve, d::PSY.Component, _) = PSY.get_max_active_power(d) -get_variable_upper_bound(::ActivePowerReserveVariable, ::PSY.Reserve, d::PSY.Storage, _) = PSY.get_output_active_power_limits(d).max -get_variable_lower_bound(::ActivePowerReserveVariable, ::PSY.Reserve, ::PSY.Component, _) = 0.0 +function get_variable_upper_bound(::ActivePowerReserveVariable, r::PSY.Reserve, d::PSY.Device, _) + return PSY.get_max_output_fraction(r) * PSY.get_max_active_power(d) +end +get_variable_lower_bound(::ActivePowerReserveVariable, ::PSY.Reserve, ::PSY.Device, _) = 0.0 ############################### ActivePowerReserveVariable, ReserveNonSpinning ######################################### - get_variable_binary(::ActivePowerReserveVariable, ::Type{<:PSY.ReserveNonSpinning}, ::AbstractReservesFormulation) = false -get_variable_upper_bound(::ActivePowerReserveVariable, ::PSY.ReserveNonSpinning, d::PSY.Component, _) = PSY.get_max_active_power(d) -get_variable_upper_bound(::ActivePowerReserveVariable, ::PSY.ReserveNonSpinning, d::PSY.Storage, _) = PSY.get_output_active_power_limits(d).max -get_variable_lower_bound(::ActivePowerReserveVariable, ::PSY.ReserveNonSpinning, ::PSY.Component, _) = 0.0 +function get_variable_upper_bound(::ActivePowerReserveVariable, r::PSY.ReserveNonSpinning, d::PSY.Device, _) + return PSY.get_max_output_fraction(r) * PSY.get_max_active_power(d) +end +get_variable_lower_bound(::ActivePowerReserveVariable, ::PSY.ReserveNonSpinning, ::PSY.Device, _) = 0.0 ############################### ServiceRequirementVariable, ReserveDemandCurve ################################ From a6b2bcf5fd3fea105a92c49b3a1e4ed7eafca4d2 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 31 Aug 2023 15:45:21 -0600 Subject: [PATCH 298/370] add participation factor constraint --- src/core/constraints.jl | 1 + src/services_models/reserve_group.jl | 1 - src/services_models/reserves.jl | 47 +++++++++++++++++++++ src/services_models/services_constructor.jl | 30 +++++++++++++ 4 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/core/constraints.jl b/src/core/constraints.jl index 1771a0b784..d0a037c6e4 100644 --- a/src/core/constraints.jl +++ b/src/core/constraints.jl @@ -69,6 +69,7 @@ struct NetworkFlowConstraint <: ConstraintType end struct NodalBalanceActiveConstraint <: ConstraintType end struct NodalBalanceReactiveConstraint <: ConstraintType end struct ParticipationAssignmentConstraint <: ConstraintType end +struct ParticipationFractionConstraint <: ConstraintType end struct PieceWiseLinearCostConstraint <: ConstraintType end struct RampConstraint <: ConstraintType end struct RampLimitConstraint <: ConstraintType end diff --git a/src/services_models/reserve_group.jl b/src/services_models/reserve_group.jl index d4628f977f..83cf3884b1 100644 --- a/src/services_models/reserve_group.jl +++ b/src/services_models/reserve_group.jl @@ -10,7 +10,6 @@ function get_default_attributes( return Dict{String, Any}() end - ############################### Reserve Variables` ######################################### """ This function checks if the variables for reserves were created diff --git a/src/services_models/reserves.jl b/src/services_models/reserves.jl index 578a7de7cc..1735b893a6 100644 --- a/src/services_models/reserves.jl +++ b/src/services_models/reserves.jl @@ -149,6 +149,53 @@ function add_constraints!( return end +function add_constraints!( + container::OptimizationContainer, + T::Type{ParticipationFractionConstraint}, + service::SR, + contributing_devices::U, + ::ServiceModel{SR, V}, +) where { + SR <: PSY.AbstractReserve, + V <: AbstractReservesFormulation, + U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, +} where {D <: PSY.Device} + time_steps = get_time_steps(container) + service_name = PSY.get_name(service) + cons = add_constraints_container!( + container, + T(), + SR, + [PSY.get_name(d) for d in contributing_devices], + time_steps; + meta = service_name, + ) + var_r = get_variable(container, ActivePowerReserveVariable(), SR, service_name) + max_participation_factor = PSY.max_participation_factor(service) + jump_model = get_jump_model(container) + requirement = PSY.get_requirement(service) + ts_vector = get_time_series(container, service, "requirement") + param_container = + get_parameter(container, RequirementTimeSeriesParameter(), SR, service_name) + param = get_parameter_column_refs(param_container, service_name) + for t in time_steps, d in contributing_devices + if parameters + cons[service_name, t] = + JuMP.@constraint( + jump_model, + var_r[name, t] <= param[t] * requirement * max_participation_factor + ) + else + cons[service_name, t] = JuMP.@constraint( + jump_model, + var_r[name, t] <= ts_vector[t] * requirement * max_participation_factor + ) + end + end + + return +end + function add_constraints!( container::OptimizationContainer, T::Type{RequirementConstraint}, diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index 5992bf7b35..220f2cddd7 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -358,6 +358,14 @@ function construct_service!( model, ) + add_constraints!( + container, + ParticipationFractionConstraint, + service, + contributing_services, + model, + ) + add_constraint_dual!(container, sys, model) return end @@ -401,6 +409,13 @@ function construct_service!( add_constraints!(container, RequirementConstraint, service, contributing_devices, model) add_constraints!(container, RampConstraint, service, contributing_devices, model) + add_constraints!( + container, + ParticipationFractionConstraint, + service, + contributing_services, + model, + ) objective_function!(container, service, model) @@ -455,6 +470,14 @@ function construct_service!( model, ) + add_constraints!( + container, + ParticipationFractionConstraint, + service, + contributing_services, + model, + ) + objective_function!(container, service, model) add_feedforward_constraints!(container, model, service) @@ -526,6 +549,13 @@ function construct_service!( ) end + add_constraints!( + container, + ParticipationFractionConstraint, + service, + contributing_services, + model, + ) add_constraints!(container, InterfaceFlowLimit, service, model) add_feedforward_constraints!(container, model, service) add_constraint_dual!(container, sys, model) From e0d971510d88bde996f13f07bfa4559093d59d16 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 31 Aug 2023 19:23:07 -0600 Subject: [PATCH 299/370] don't add constraints if factor is 1.0 --- src/services_models/reserves.jl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/services_models/reserves.jl b/src/services_models/reserves.jl index 1735b893a6..a2be43e5ea 100644 --- a/src/services_models/reserves.jl +++ b/src/services_models/reserves.jl @@ -160,6 +160,12 @@ function add_constraints!( V <: AbstractReservesFormulation, U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, } where {D <: PSY.Device} + max_participation_factor = PSY.max_participation_factor(service) + + if max_participation_factor >= 1.0 + return + end + time_steps = get_time_steps(container) service_name = PSY.get_name(service) cons = add_constraints_container!( @@ -171,7 +177,6 @@ function add_constraints!( meta = service_name, ) var_r = get_variable(container, ActivePowerReserveVariable(), SR, service_name) - max_participation_factor = PSY.max_participation_factor(service) jump_model = get_jump_model(container) requirement = PSY.get_requirement(service) ts_vector = get_time_series(container, service, "requirement") From b5970a8762caf675a2c60b0c93ed9b0a9491c163 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 1 Sep 2023 09:11:53 -0600 Subject: [PATCH 300/370] fix reserve tests --- src/services_models/reserves.jl | 3 ++- src/services_models/services_constructor.jl | 12 ++---------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/src/services_models/reserves.jl b/src/services_models/reserves.jl index a2be43e5ea..9876433568 100644 --- a/src/services_models/reserves.jl +++ b/src/services_models/reserves.jl @@ -7,6 +7,7 @@ get_variable_binary(::ActivePowerReserveVariable, ::Type{<:PSY.Reserve}, ::Abstr function get_variable_upper_bound(::ActivePowerReserveVariable, r::PSY.Reserve, d::PSY.Device, _) return PSY.get_max_output_fraction(r) * PSY.get_max_active_power(d) end +get_variable_upper_bound(::ActivePowerReserveVariable, r::PSY.ReserveDemandCurve, d::PSY.Device, _) = PSY.get_max_active_power(d) get_variable_lower_bound(::ActivePowerReserveVariable, ::PSY.Reserve, ::PSY.Device, _) = 0.0 ############################### ActivePowerReserveVariable, ReserveNonSpinning ######################################### @@ -160,7 +161,7 @@ function add_constraints!( V <: AbstractReservesFormulation, U <: Union{Vector{D}, IS.FlattenIteratorWrapper{D}}, } where {D <: PSY.Device} - max_participation_factor = PSY.max_participation_factor(service) + max_participation_factor = PSY.get_max_participation_factor(service) if max_participation_factor >= 1.0 return diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index 220f2cddd7..858f6bc19d 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -358,14 +358,6 @@ function construct_service!( model, ) - add_constraints!( - container, - ParticipationFractionConstraint, - service, - contributing_services, - model, - ) - add_constraint_dual!(container, sys, model) return end @@ -413,7 +405,7 @@ function construct_service!( container, ParticipationFractionConstraint, service, - contributing_services, + contributing_devices, model, ) @@ -474,7 +466,7 @@ function construct_service!( container, ParticipationFractionConstraint, service, - contributing_services, + contributing_devices, model, ) From b85e772a265f07fbea8d8cda0bf32e0ef7055ee1 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 1 Sep 2023 09:45:45 -0600 Subject: [PATCH 301/370] add export for new constraint --- src/PowerSimulations.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index ca6f9b8000..82f3a32b7e 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -290,6 +290,7 @@ export NodalBalanceReactiveConstraint export OutputActivePowerVariableLimitsConstraint export PieceWiseLinearCostConstraint export ParticipationAssignmentConstraint +export ParticipationFractionConstraint export PhaseAngleControlLimit export RampConstraint export RampLimitConstraint From 885fcfd2a28017dd887137d4bcc0541922c8f248 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 1 Sep 2023 09:46:01 -0600 Subject: [PATCH 302/370] fix the check for parameters --- src/services_models/reserves.jl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/services_models/reserves.jl b/src/services_models/reserves.jl index 9876433568..8f84022c0d 100644 --- a/src/services_models/reserves.jl +++ b/src/services_models/reserves.jl @@ -121,7 +121,7 @@ function add_constraints!( use_slacks && (slack_vars = reserve_slacks!(container, service)) requirement = PSY.get_requirement(service) jump_model = get_jump_model(container) - if parameters + if built_for_recurrent_solves(container) param_container = get_parameter(container, RequirementTimeSeriesParameter(), SR, service_name) param = get_parameter_column_refs(param_container, service_name) @@ -185,14 +185,15 @@ function add_constraints!( get_parameter(container, RequirementTimeSeriesParameter(), SR, service_name) param = get_parameter_column_refs(param_container, service_name) for t in time_steps, d in contributing_devices - if parameters - cons[service_name, t] = + name = PSY.get_name(d) + if built_for_recurrent_solves(container) + cons[name, t] = JuMP.@constraint( jump_model, var_r[name, t] <= param[t] * requirement * max_participation_factor ) else - cons[service_name, t] = JuMP.@constraint( + cons[name, t] = JuMP.@constraint( jump_model, var_r[name, t] <= ts_vector[t] * requirement * max_participation_factor ) From 7f598b7093989d163ac31924427a1321cac04ce7 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 1 Sep 2023 09:46:08 -0600 Subject: [PATCH 303/370] fix more tests --- src/services_models/services_constructor.jl | 16 ++++- test/test_services_constructor.jl | 74 +++++++++++++++++++-- 2 files changed, 84 insertions(+), 6 deletions(-) diff --git a/src/services_models/services_constructor.jl b/src/services_models/services_constructor.jl index 858f6bc19d..fa6fc7c98f 100644 --- a/src/services_models/services_constructor.jl +++ b/src/services_models/services_constructor.jl @@ -125,7 +125,13 @@ function construct_service!( contributing_devices = get_contributing_devices(model) add_constraints!(container, RequirementConstraint, service, contributing_devices, model) - + add_constraints!( + container, + ParticipationFractionConstraint, + service, + contributing_devices, + model, + ) objective_function!(container, service, model) add_feedforward_constraints!(container, model, service) @@ -172,7 +178,13 @@ function construct_service!( contributing_devices = get_contributing_devices(model) add_constraints!(container, RequirementConstraint, service, contributing_devices, model) - + add_constraints!( + container, + ParticipationFractionConstraint, + service, + contributing_devices, + model, + ) objective_function!(container, service, model) add_feedforward_constraints!(container, model, service) diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index 9c4100a19c..f6aed68239 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -22,19 +22,22 @@ @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT moi_tests(model, 648, 0, 120, 216, 72, false) reserve_variables = [ - :ActivePowerReserveVariable__VariableReserve_ReserveUp_Reserve1 - :ActivePowerReserveVariable__ReserveDemandCurve_ReserveUp_ORDC1 - :ActivePowerReserveVariable__VariableReserve_ReserveDown_Reserve2 - :ActivePowerReserveVariable__VariableReserve_ReserveUp_Reserve11 + :ActivePowerReserveVariable__VariableReserve__ReserveUp__Reserve1 + :ActivePowerReserveVariable__ReserveDemandCurve__ReserveUp__ORDC1 + :ActivePowerReserveVariable__VariableReserve__ReserveDown__Reserve2 + :ActivePowerReserveVariable__VariableReserve__ReserveUp__Reserve11 ] + found_vars = 0 for (k, var_array) in model.internal.container.variables if PSI.encode_key(k) in reserve_variables for var in var_array @test JuMP.has_lower_bound(var) @test JuMP.lower_bound(var) == 0.0 end + found_vars += 1 end end + @test found_vars == 4 end @testset "Test Ramp Reserves from Thermal Dispatch" begin @@ -325,3 +328,66 @@ end @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT moi_tests(model, 456, 0, 120, 264, 24, false) end + +@testset "Test Reserves with Participation factor limits" begin + c_sys5_uc = PSB.build_system(PSITestSystems, "c_sys5_uc"; add_reserves = true) + for service in get_components(Reserve, c_sys5_uc) + set_max_participation_factor!(service, 0.8) + end + + template = get_thermal_dispatch_template_network(CopperPlatePowerModel) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve1"), + ) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveUp}, RangeReserve, "Reserve11"), + ) + set_service_model!( + template, + ServiceModel(VariableReserve{ReserveDown}, RangeReserve, "Reserve2"), + ) + set_service_model!( + template, + ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), + ) + + + model = DecisionModel(template, c_sys5_uc) + @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT + moi_tests(model, 648, 0, 384, 216, 72, false) + reserve_variables = [ + :ActivePowerReserveVariable__VariableReserve__ReserveUp__Reserve1 + :ActivePowerReserveVariable__ReserveDemandCurve__ReserveUp__ORDC1 + :ActivePowerReserveVariable__VariableReserve__ReserveDown__Reserve2 + :ActivePowerReserveVariable__VariableReserve__ReserveUp__Reserve11 + ] + found_vars = 0 + for (k, var_array) in model.internal.container.variables + @show PSI.encode_key(k) + if PSI.encode_key(k) in reserve_variables + for var in var_array + @test JuMP.has_lower_bound(var) + @test JuMP.lower_bound(var) == 0.0 + end + found_vars += 1 + end + end + @test found_vars == 4 + + participation_constraints = [ + :ParticipationFractionConstraint__VariableReserve__ReserveUp__Reserve11, + :ParticipationFractionConstraint__VariableReserve__ReserveDown__Reserve2 + ] + + found_constraints = 0 + + for (k, _) in model.internal.container.constraints + if PSI.encode_key(k) in participation_constraints + found_constraints += 1 + end + end + + @test found_constraints == 2 +end From b543e3bc82ba17bbe6d1d2e9ce589645f695c380 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 1 Sep 2023 09:47:32 -0600 Subject: [PATCH 304/370] remove scripts --- scripts/create_rts_systems.jl | 378 ---------------------------- scripts/debug_emulation_psi.jl | 72 ------ scripts/formatter/Project.toml | 10 - scripts/formatter/formatter_code.jl | 28 --- scripts/rts_simulation_setup.jl | 197 --------------- scripts/script_utils.jl | 73 ------ scripts/test_emulation_psi.jl | 72 ------ 7 files changed, 830 deletions(-) delete mode 100644 scripts/create_rts_systems.jl delete mode 100644 scripts/debug_emulation_psi.jl delete mode 100644 scripts/formatter/Project.toml delete mode 100644 scripts/formatter/formatter_code.jl delete mode 100644 scripts/rts_simulation_setup.jl delete mode 100644 scripts/script_utils.jl delete mode 100644 scripts/test_emulation_psi.jl diff --git a/scripts/create_rts_systems.jl b/scripts/create_rts_systems.jl deleted file mode 100644 index 3466df006f..0000000000 --- a/scripts/create_rts_systems.jl +++ /dev/null @@ -1,378 +0,0 @@ -using Pkg -Pkg.activate("test") -Pkg.instantiate() -using Revise - -using PowerSimulations -using PowerSystems -using PowerSystemCaseBuilder -using InfrastructureSystems -const PSY = PowerSystems -const PSI = PowerSimulations -const PSB = PowerSystemCaseBuilder -using Xpress -using JuMP -using Logging -using Dates -using TimeSeries -using Random -rng = MersenneTwister(1234) -using Interpolations -using Distributions - -sys_DA = PSB.build_RTS_GMLC_DA_sys_noTS(; raw_data = PSB.RTS_DIR) -sys_RT = PSB.build_RTS_GMLC_RT_sys_noTS(; raw_data = PSB.RTS_DIR) -sys_RT_HourAhead = PSB.build_RTS_GMLC_RT_sys_noTS(; raw_data = PSB.RTS_DIR) - -reserve_hydro = true # use false to remove hydro from the reserve provision devices - -area_maps_regup = Dict() -area_maps_regup["1"] = "Reg_Up_R1" -area_maps_regup["2"] = "Reg_Up_R2" -area_maps_regup["3"] = "Reg_Up_R3" - -area_maps_regdn = Dict() -area_maps_regdn["1"] = "Reg_Down_R1" -area_maps_regdn["2"] = "Reg_Down_R2" -area_maps_regdn["3"] = "Reg_Down_R3" - -area_maps_spin = Dict() -area_maps_spin["1"] = "Spin_Up_R1" -area_maps_spin["2"] = "Spin_Up_R2" -area_maps_spin["3"] = "Spin_Up_R3" - -for sys in [sys_DA, sys_RT, sys_RT_HourAhead] - # Adjust Reserve Provisions - # Remove Flex Reserves - res_up = get_component(VariableReserve{ReserveUp}, sys, "Flex_Up") - if !isnothing(res_up) - remove_component!(sys, res_up) - end - res_dn = get_component(VariableReserve{ReserveDown}, sys, "Flex_Down") - if !isnothing(res_dn) - remove_component!(sys, res_dn) - end - mult = 1.0 - # Reg Up Split - reg_reserve_up = get_component(VariableReserve, sys, "Reg_Up") - set_requirement!(reg_reserve_up, mult * get_requirement(reg_reserve_up)) - for name in ["Reg_Up_R1", "Reg_Up_R2", "Reg_Up_R3"] - reg_zone = PSY.VariableReserve{ReserveUp}(; - name = name, - available = true, - time_frame = reg_reserve_up.time_frame, - requirement = reg_reserve_up.requirement / 3.0, - ) - old_ts = get_time_series(SingleTimeSeries, reg_reserve_up, "requirement") - add_component!(sys, reg_zone) - add_time_series!(sys, reg_zone, old_ts) - end - remove_component!(sys, reg_reserve_up) - # Reg Down Split - reg_reserve_dn = get_component(VariableReserve, sys, "Reg_Down") - set_requirement!(reg_reserve_dn, mult * get_requirement(reg_reserve_dn)) - for name in ["Reg_Down_R1", "Reg_Down_R2", "Reg_Down_R3"] - reg_zone = PSY.VariableReserve{ReserveDown}(; - name = name, - available = true, - time_frame = reg_reserve_dn.time_frame, - requirement = reg_reserve_dn.requirement / 3.0, - ) - old_ts = get_time_series(SingleTimeSeries, reg_reserve_dn, "requirement") - add_component!(sys, reg_zone) - add_time_series!(sys, reg_zone, old_ts) - end - remove_component!(sys, reg_reserve_dn) - - spin_reserve_R1 = get_component(VariableReserve, sys, "Spin_Up_R1") - spin_reserve_R2 = get_component(VariableReserve, sys, "Spin_Up_R2") - spin_reserve_R3 = get_component(VariableReserve, sys, "Spin_Up_R3") - - for g in get_components(Generator, sys) - clear_services!(g) - end - # Remove Destillate Fuel from sys and update services - for g in get_components( - x -> x.prime_mover in [PrimeMovers.CT, PrimeMovers.CC], - ThermalStandard, - sys, - ) - if get_fuel(g) == ThermalFuels.DISTILLATE_FUEL_OIL - remove_component!(sys, g) - continue - end - g.operation_cost.shut_down = g.operation_cost.start_up / 2.0 - - #= - # Small generators do not participate in reg - if PSY.get_base_power(g) > 3.0 - clear_services!(g) - add_service!(g, reg_reserve_dn) - add_service!(g, reg_reserve_up) - continue - end - =# - area_name = get_name(get_area(get_bus(g))) - reg_up = get_component(VariableReserve, sys, area_maps_regup[area_name]) - reg_dn = get_component(VariableReserve, sys, area_maps_regdn[area_name]) - add_service!(g, reg_up, sys) - add_service!(g, reg_dn, sys) - - # Update costs to avoid degenerate solutions in thermal - if get_prime_mover(g) == PrimeMovers.CT - set_status!(g, false) - set_active_power!(g, 0.0) - old_pwl_array = get_variable(get_operation_cost(g)) |> get_cost - new_pwl_array = similar(old_pwl_array) - for (ix, tup) in enumerate(old_pwl_array) - if ix ∈ [1, length(old_pwl_array)] - cost_noise = 50.0 * rand() - new_pwl_array[ix] = ((tup[1] + cost_noise), tup[2]) - else - try_again = true - while try_again - cost_noise = 50.0 * rand() - power_noise = 0.01 * rand() - slope_previous = - ((tup[1] + cost_noise) - old_pwl_array[ix - 1][1]) / - ((tup[2] - power_noise) - old_pwl_array[ix - 1][2]) - slope_next = - (-(tup[1] + cost_noise) + old_pwl_array[ix + 1][1]) / - (-(tup[2] - power_noise) + old_pwl_array[ix + 1][2]) - new_pwl_array[ix] = ((tup[1] + cost_noise), (tup[2] - power_noise)) - try_again = slope_previous > slope_next - end - end - end - get_variable(get_operation_cost(g)).cost = new_pwl_array - end - end - - for g in get_components( - x -> !(x.prime_mover in [PrimeMovers.CT, PrimeMovers.CC]), - ThermalStandard, - sys, - ) - get_operation_cost(g).shut_down = get_operation_cost(g).start_up / 2.0 - area_name = get_name(get_area(get_bus(g))) - reg_up = get_component(VariableReserve, sys, area_maps_regup[area_name]) - reg_dn = get_component(VariableReserve, sys, area_maps_regdn[area_name]) - reg_spin = get_component(VariableReserve, sys, area_maps_spin[area_name]) - if !(get_fuel(g) == ThermalFuels.NUCLEAR) - add_service!(g, reg_up, sys) - add_service!(g, reg_dn, sys) - add_service!(g, reg_spin, sys) - end - end - - #= - for g in get_components(RenewableDispatch, sys) - set_operation_cost!(g, TwoPartCost(0.0, 0.0)) - area_name = get_name(get_area(get_bus(g))) - reg_up = get_component(VariableReserve, sys, area_maps_regup[area_name]) - reg_dn = get_component(VariableReserve, sys, area_maps_regdn[area_name]) - reg_spin = get_component(VariableReserve, sys, area_maps_spin[area_name]) - add_service!(g, reg_up, sys) - add_service!(g, reg_dn, sys) - add_service!(g, reg_spin, sys) - end - =# - - #= - for g in get_components(HydroEnergyReservoir, sys) - area_name = get_name(get_area(get_bus(g))) - reg_up = get_component(VariableReserve, sys, area_maps_regup[area_name]) - reg_dn = get_component(VariableReserve, sys, area_maps_regdn[area_name]) - reg_spin = get_component(VariableReserve, sys, area_maps_spin[area_name]) - add_service!(g, reg_up, sys) - add_service!(g, reg_dn, sys) - add_service!(g, reg_spin, sys) - end - =# - - #Remove units that make no sense to include - names = [ - "114_SYNC_COND_1", - "314_SYNC_COND_1", - "313_STORAGE_1", - "214_SYNC_COND_1", - "212_CSP_1", - ] - for d in get_components(x -> x.name ∈ names, Generator, sys) - remove_component!(sys, d) - end - for br in get_components(DCBranch, sys) - remove_component!(sys, br) - end - for d in get_components(Storage, sys) - remove_component!(sys, d) - end - - # Update Ramp Limits - for d in - get_components(x -> (occursin(r"STEAM|NUCLEAR", get_name(x))), ThermalStandard, sys) - - #get_fuel(d) == ThermalFuels.COAL && set_ramp_limits!(d, (up = 0.001, down = 0.001)) - - #if get_rating(d) < 3.0 - # set_status!(d, false) - # clear_services!(d) - #reserve_hydro && add_service!(d, reg_reserve_up) - #reserve_hydro && add_service!(d, reg_reserve_dn) - #add_service!(d, spin_reserve_R1, sys) - # set_active_power!(d, 0.0) - # continue - #end - get_operation_cost(d).shut_down = get_operation_cost(d).start_up / 2.0 - if get_fuel(d) == ThermalFuels.NUCLEAR - set_ramp_limits!(d, (up = 0.0, down = 0.0)) - set_time_limits!(d, (up = 4380.0, down = 4380.0)) - end - end - - # Remove bad Hydro - for d in get_components(HydroDispatch, sys) - remove_component!(sys, d) - end - - #= - for area in get_components(Area, sys) - if get_name(area) == "1" - continue - end - remove_component!(sys, area) - end - for b in get_components(Bus, sys) - set_area!(b, get_component(Area, sys, "1")) - end - =# -end - -horizon_DA = 48 -interval_DA = Hour(24) -horizon_RT = 24 -interval_RT = Minute(5) -horizon_HourAhead = 24 -interval_HourAhead = Hour(1) - -transform_single_time_series!(sys_DA, horizon_DA, interval_DA) -transform_single_time_series!(sys_RT, horizon_RT, interval_RT) -transform_single_time_series!(sys_RT_HourAhead, horizon_HourAhead, interval_HourAhead) - -to_json(sys_DA, "data/sys_DA_1h.json"; force = true) -to_json(sys_RT, "data/sys_RT_5min.json"; force = true) -to_json(sys_RT_HourAhead, "data/sys_RT_HourAhead_2hours.json"; force = true) - -########################################################################################## -################################## Here AGC code starts ################################## -########################################################################################## - -sys_AGC = deepcopy(sys_RT) -remove_time_series!(sys_AGC, DeterministicSingleTimeSeries) -remove_time_series!(sys_AGC, SingleTimeSeries) - -init_time = DateTime("2020-01-01T00:00:00") -final_time = DateTime("2020-12-31T23:59:56") -end_time = DateTime("2020-12-31T23:55:00") - -for type in [RenewableFix, ElectricLoad] - for d in get_components(type, sys_RT) - @show get_name(d) - for l in get_time_series_names(SingleTimeSeries, d) - step_time = Minute(5) - step_range = Int(Minute(5) / Second(4)) - _dates = range(init_time, final_time; step = Second(4)) - time_series = get_time_series(SingleTimeSeries, d, l) - total_interp_timeseries = Vector{Float64}(undef, size(_dates)[1]) - current_date = init_time - i = 0 - while current_date < end_time - t_stamps = range(current_date; step = Second(4), length = step_range) - val_init = values(time_series[current_date].data)[1] - val_next = values(time_series[current_date + step_time].data)[1] - _vals = range(1, 2; length = step_range) - interp_vals = LinearInterpolation(1:2, [val_init, val_next])(_vals) - if type <: ElectricLoad - noise = rand(Normal(0.0, 0.025), step_range) - else - noise = rand(Normal(0.0, 0.1), step_range) - end - interp_vals .+= noise - total_interp_timeseries[(i * step_range + 1):((i + 1) * step_range)] = - interp_vals - current_date += step_time - i = i + 1 - end - data = TimeArray(_dates, max.(total_interp_timeseries, 0.0)) - ts = SingleTimeSeries(l, data) - c = get_component(typeof(d), sys_AGC, get_name(d)) - add_time_series!(sys_AGC, c, ts) - end - end -end - -#= -for g in get_components(ThermalStandard, sys_AGC) - _date = DateTime("2020-09-01") - step_time = Hour(1) - current_date = deepcopy(_date) - while current_date < DateTime("2020-09-11") - t_stamps = range(current_date, step = Second(4), length = 900) - vals = zeros(length(t_stamps)) - forecast = Deterministic("get_rating", TimeArray(t_stamps, vals)) - add_forecast!(sys_AGC, g, forecast) - current_date += step_time - end -end - -for g in get_components(RenewableDispatch, sys_AGC) - _date = DateTime("2020-09-01") - step_time = Hour(1) - current_date = deepcopy(_date) - while current_date < DateTime("2020-09-11") - t_stamps = range(current_date, step = Second(4), length = 900) - vals = zeros(length(t_stamps)) - forecast = Deterministic("get_rating", TimeArray(t_stamps, vals)) - add_forecast!(sys_AGC, g, forecast) - current_date += step_time - end -end -=# - -for area in get_components(Area, sys_AGC) - AGC_service = PSY.AGC(; - name = "AGC_Area_$(area)", - available = true, - bias = 739.0, - K_p = 2.5 + rand(Normal(0.0, 0.025), 1)[1], - K_i = max(0.1 + rand(Normal(0.0, 0.00025), 1)[1], 0.001), - K_d = 0.0, - delta_t = 4, - area = get_component(Area, sys_AGC, get_name(area)), - ) - - contributing_devices = Vector{PSY.Device}() - reg_reserve_up = - get_component(VariableReserve, sys_AGC, area_maps_regup[get_name(area)]) - for g in get_components(x -> x.bus.area == area, Generator, sys_AGC) - if has_service(g, reg_reserve_up) - droop = if isa(g, ThermalStandard) - 0.04 * PSY.get_base_power(g) - else - 0.05 * PSY.get_base_power(g) - end - p_factor = (up = 1.0, dn = 1.0) - t = RegulationDevice(g; participation_factor = p_factor, droop = droop) - add_component!(sys_AGC, t) - push!(contributing_devices, t) - end - end - - add_service!(sys_AGC, AGC_service, contributing_devices) -end - -for res in get_components(VariableReserve, sys_AGC) - remove_component!(sys_AGC, res) -end - -to_json(sys_AGC, "data/sys_AGC_4sec.json"; force = true) diff --git a/scripts/debug_emulation_psi.jl b/scripts/debug_emulation_psi.jl deleted file mode 100644 index c58dee29b0..0000000000 --- a/scripts/debug_emulation_psi.jl +++ /dev/null @@ -1,72 +0,0 @@ -using Pkg -Pkg.activate("test") -Pkg.instantiate() -using Revise - -using PowerSimulations -using PowerSystems -using PowerSystemCaseBuilder -using InfrastructureSystems -const PSY = PowerSystems -const PSI = PowerSimulations -const PSB = PowerSystemCaseBuilder -using Xpress -using JuMP -using Logging -using Dates -using TimeSeries - -c_sys5_reg = PSB.build_system(PSITestSystems, "c_sys5_reg") - -# Transform Deterministic to Static -load_dict = Dict() -for load in get_components(PowerLoad, c_sys5_reg) - name = get_name(load) - t_array = get_time_series_array( - Deterministic, - load, - "max_active_power"; - start_time = DateTime("2024-01-01T00:00:00"), - ) - load_dict[name] = collect(values(t_array)) -end - -reg_dict = Dict() -for dev in get_components(RegulationDevice, c_sys5_reg) - name = get_name(dev) - t_array = get_time_series_array( - Deterministic, - dev, - "max_active_power"; - start_time = DateTime("2024-01-01T00:00:00"), - ) - reg_dict[name] = collect(values(t_array)) -end - -remove_time_series!(c_sys5_reg, Deterministic) - -resolution = Dates.Hour(1) -dates = range(DateTime("2024-01-01T00:00:00"); step = resolution, length = 24) -c_sys5_reg - -for load in get_components(PowerLoad, c_sys5_reg) - name = get_name(load) - t_array = load_dict[name] - data = TimeArray(dates, t_array) - ts = SingleTimeSeries("max_active_power", data) - add_time_series!(c_sys5_reg, load, ts) -end - -for dev in get_components(RegulationDevice, c_sys5_reg) - name = get_name(dev) - t_array = reg_dict[name] - data = TimeArray(dates, t_array) - ts = SingleTimeSeries("max_active_power", data) - add_time_series!(c_sys5_reg, dev, ts) -end - -template_agc = template_agc_reserve_deployment() -model = EmulationModel(template_agc, c_sys5_reg; optimizer = Xpress.Optimizer) -build!(model; executions = 23, output_dir = mktempdir(; cleanup = true)) - -run!(model) diff --git a/scripts/formatter/Project.toml b/scripts/formatter/Project.toml deleted file mode 100644 index a33f747b58..0000000000 --- a/scripts/formatter/Project.toml +++ /dev/null @@ -1,10 +0,0 @@ -uuid = "c6367ca8-164d-4469-afe3-c91cf8860505" -authors = ["Jose Daniel Lara "] - -[deps] -JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899" -Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" - -[compat] -JuliaFormatter = "1.0" -julia = "^1.7" diff --git a/scripts/formatter/formatter_code.jl b/scripts/formatter/formatter_code.jl deleted file mode 100644 index 75bc991e6f..0000000000 --- a/scripts/formatter/formatter_code.jl +++ /dev/null @@ -1,28 +0,0 @@ -using Pkg -Pkg.activate(@__DIR__) -Pkg.instantiate() -Pkg.update() - -using JuliaFormatter - -main_paths = ["."] -for main_path in main_paths - for (root, dir, files) in walkdir(main_path) - for f in files - @show file_path = abspath(root, f) - !occursin(".jl", f) && continue - format(file_path; - whitespace_ops_in_indices = true, - remove_extra_newlines = true, - verbose = true, - always_for_in = true, - whitespace_typedefs = true, - conditional_to_if = true, - join_lines_based_on_source = true, - separate_kwargs_with_semicolon = true, - - # always_use_return = true. # Disabled since it throws a lot of false positives - ) - end - end -end diff --git a/scripts/rts_simulation_setup.jl b/scripts/rts_simulation_setup.jl deleted file mode 100644 index bc71853963..0000000000 --- a/scripts/rts_simulation_setup.jl +++ /dev/null @@ -1,197 +0,0 @@ -using Pkg -Pkg.activate("test") -Pkg.instantiate() -using Revise - -using PowerSimulations -using PowerSystems -using PowerSystemCaseBuilder -using InfrastructureSystems -const PSY = PowerSystems -const PSI = PowerSimulations -const PSB = PowerSystemCaseBuilder -using Xpress -using JuMP -using Logging -using Dates -using TimeSeries -using PlotlyJS - -include("script_utils.jl") - -sys_DA = System("data/sys_DA_1h.json") -sys_RT = System("data/sys_RT_5min.json") - -mipgap = 1e-2 # 1% -num_steps = 2 -starttime = DateTime("2020-01-01T00:00:00") - -template_uc = get_uc_ptdf_template(sys_DA) -set_device_model!(template_uc, ThermalStandard, ThermalBasicUnitCommitment) -template_ed = get_ed_ptdf_template(sys_RT) -set_device_model!(template_ed, ThermalStandard, ThermalBasicDispatch) - -models = SimulationModels(; - decision_models = [ - DecisionModel( - template_uc, - sys_DA; - name = "UC", - optimizer = optimizer_with_attributes(Xpress.Optimizer, "MIPRELSTOP" => mipgap), - system_to_file = false, - initialize_model = true, - optimizer_solve_log_print = false, - direct_mode_optimizer = true, - rebuild_model = false, - store_variable_names = true, - calculate_conflict = true, - ), - DecisionModel( - template_ed, - sys_RT; - name = "ED", - optimizer = optimizer_with_attributes(Xpress.Optimizer, "MIPRELSTOP" => mipgap), - system_to_file = false, - initialize_model = true, - optimizer_solve_log_print = false, - direct_mode_optimizer = true, - rebuild_model = false, - store_variable_names = true, - calculate_conflict = true, - ), - ], -) - -# Set-up the sequence UC-ED -sequence = SimulationSequence(; - models = models, - feedforwards = Dict( - "ED" => [ - SemiContinuousFeedforward(; - component_type = ThermalStandard, - source = OnVariable, - affected_values = [ActivePowerVariable], - ), - FixValueFeedforward(; - component_type = VariableReserve{ReserveUp}, - source = ActivePowerReserveVariable, - affected_values = [ActivePowerReserveVariable], - ), - FixValueFeedforward(; - component_type = VariableReserve{ReserveDown}, - source = ActivePowerReserveVariable, - affected_values = [ActivePowerReserveVariable], - ), - ], - ), - ini_cond_chronology = InterProblemChronology(), -) - -sim = Simulation(; - name = "compact_sim", - steps = num_steps, - models = models, - sequence = sequence, - initial_time = starttime, - simulation_folder = mktempdir(; cleanup = true), -) - -build!(sim; console_level = Logging.Info, serialize = false) -execute!(sim; enable_progress_bar = true); - -results_nrb = SimulationResults(sim; ignore_status = true) -results_uc_nrb = get_decision_problem_results(results_nrb, "UC") -results_ed_nrb = get_decision_problem_results(results_nrb, "ED") - -regup_uc = read_realized_variable( - results_uc_nrb, - "ActivePowerReserveVariable__VariableReserve__ReserveUp__Reg_Up_R1", -) -dates_uc = regup_uc[!, "DateTime"] -regup_uc_st4 = regup_uc[!, "123_STEAM_2"] - -regup_ed = read_realized_parameter( - results_ed_nrb, - "FixValueParameter__VariableReserve__ReserveUp__Reg_Up_R1", -) -dates_ed = regup_ed[!, "DateTime"] -regup_ed_st4 = regup_ed[!, "123_STEAM_2"] -regup_ed_var = read_realized_variable( - results_ed_nrb, - "ActivePowerReserveVariable__VariableReserve__ReserveUp__Reg_Up_R1", -) -regup_ed_var_st4 = regup_ed_var[!, "123_STEAM_2"] - -PlotlyJS.plot([ - PlotlyJS.scatter(; x = dates_uc, y = regup_uc_st4, name = "UC", line_shape = "hv"), - PlotlyJS.scatter(; - x = dates_ed, - y = regup_ed_st4 .* 100.0, - name = "ED", - line_shape = "hv", - ), - PlotlyJS.scatter(; - x = dates_ed, - y = regup_ed_var_st4, - name = "ED Var", - line_shape = "hv", - ), -]) - -uc = sim.models.decision_models[1] -ed = sim.models.decision_models[2] -vars = ed.internal.container.variables -pwl = vars[PSI.VariableKey{PSI.PieceWiseLinearCostVariable, ThermalStandard}("")] -pwl_var = pwl["315_STEAM_1", 1, 1] -p = vars[PSI.VariableKey{ActivePowerVariable, ThermalStandard}("")] -p["315_STEAM_1", 1] -p_stuff = p["315_STEAM_1", :] -p_vals = value.(p_stuff) -value.(regup["324_PV_3", :]) - -param = ed.internal.container.parameters -on_val = param[PSI.ParameterKey{OnStatusParameter, ThermalStandard}("")].parameter_array -regup3 = - param[PSI.ParameterKey{FixValueParameter, VariableReserve{ReserveUp}}( - "Reg_Up_R3", - )].parameter_array -spinup3 = - param[PSI.ParameterKey{FixValueParameter, VariableReserve{ReserveUp}}( - "Spin_Up_R3", - )].parameter_array -regdown3 = - param[PSI.ParameterKey{FixValueParameter, VariableReserve{ReserveDown}}( - "Reg_Down_R3", - )].parameter_array -regup3["315_STEAM_1", :] -regdown3["315_STEAM_1", :] -spinup3["315_STEAM_1", :] -on_val_steam = JuMP.fix_value.(on_val["315_STEAM_1", :]) - -g = get_component(ThermalStandard, sys_RT, "315_STEAM_1") -g.bus - -var_state = sim.internal.simulation_state.decision_states.variables -on_state = var_state[PSI.VariableKey{OnVariable, ThermalStandard}("")] -regup_state3 = - var_state[PSI.VariableKey{ActivePowerReserveVariable, VariableReserve{ReserveDown}}( - "Reg_Down_R3", - )] -reg_val = regup_state3.values[!, "315_STEAM_1"] - -constr = ed.internal.container.constraints -ub_ff = constr[PSI.ConstraintKey{FeedforwardSemiContinousConstraint, ThermalStandard}( - "ActivePowerVariable_ub", -)] -ub_ff["315_STEAM_1", :] - -#= -Name Type Sense Bound -R3217 row LE .0000000:00:00 -C4 column LO .000000 -C1598 column UP .000000 -C10643 column LO 1.000000 -C11317 column LO 1.000000 -=# - -# ActivePowerVariable_ThermalStandard_{322_CT_6, 1} - 0.55 _[1465] + ActivePowerReserveVariable_VariableReserve{ReserveUp}_Reg_Up_R3_{322_CT_6, 1} - x[322_CT_6,1] ≤ 0.0 diff --git a/scripts/script_utils.jl b/scripts/script_utils.jl deleted file mode 100644 index 91220bddfb..0000000000 --- a/scripts/script_utils.jl +++ /dev/null @@ -1,73 +0,0 @@ -############################### -###### Model Templates ######## -############################### - -# Some models are commented for RTS model - -function set_uc_models!(template_uc) - set_device_model!(template_uc, ThermalStandard, ThermalStandardUnitCommitment) - set_device_model!(template_uc, RenewableDispatch, RenewableFullDispatch) - set_device_model!(template_uc, RenewableFix, FixedOutput) - set_device_model!(template_uc, PowerLoad, StaticPowerLoad) - set_device_model!(template_uc, TapTransformer, StaticBranchUnbounded) - set_device_model!(template_uc, HydroEnergyReservoir, HydroDispatchRunOfRiver) - set_service_model!( - template_uc, - ServiceModel(VariableReserve{ReserveUp}, RangeReserve; use_slacks = true), - ) - set_service_model!( - template_uc, - ServiceModel(VariableReserve{ReserveDown}, RangeReserve; use_slacks = true), - ) - return -end - -############################### -###### Get Templates ########## -############################### - -### PTDF Bounded #### - -function get_uc_ptdf_template(sys) - template_uc = ProblemTemplate( - NetworkModel( - StandardPTDFModel; - use_slacks = false, - PTDF_matrix = PTDF(sys), - duals = [CopperPlateBalanceConstraint], - ), - ) - set_uc_models!(template_uc) - set_device_model!(template_uc, Line, StaticBranch) - return template_uc -end - -function get_ed_ptdf_template(sys) - template_ed = ProblemTemplate( - NetworkModel( - StandardPTDFModel; - use_slacks = true, - PTDF_matrix = PTDF(sys), - duals = [CopperPlateBalanceConstraint], - ), - ) - set_uc_models!(template_ed) - set_device_model!(template_ed, ThermalStandard, ThermalStandardDispatch) - return template_ed -end - -#### PTDF Unbounded #### - -function get_uc_ptdf_unbounded_template(sys) - template_uc = get_uc_ptdf_template(sys) - set_device_model!(template_uc, Line, StaticBranchUnbounded) - return template_uc -end - -function get_ed_ptdf_unbounded_template(sys_rts_rt) - template_ed = get_ed_ptdf_template(sys_rts_rt) - set_device_model!(template_uc, Line, StaticBranchUnbounded) - return template_ed -end - -####### Simulations ##### diff --git a/scripts/test_emulation_psi.jl b/scripts/test_emulation_psi.jl deleted file mode 100644 index c58dee29b0..0000000000 --- a/scripts/test_emulation_psi.jl +++ /dev/null @@ -1,72 +0,0 @@ -using Pkg -Pkg.activate("test") -Pkg.instantiate() -using Revise - -using PowerSimulations -using PowerSystems -using PowerSystemCaseBuilder -using InfrastructureSystems -const PSY = PowerSystems -const PSI = PowerSimulations -const PSB = PowerSystemCaseBuilder -using Xpress -using JuMP -using Logging -using Dates -using TimeSeries - -c_sys5_reg = PSB.build_system(PSITestSystems, "c_sys5_reg") - -# Transform Deterministic to Static -load_dict = Dict() -for load in get_components(PowerLoad, c_sys5_reg) - name = get_name(load) - t_array = get_time_series_array( - Deterministic, - load, - "max_active_power"; - start_time = DateTime("2024-01-01T00:00:00"), - ) - load_dict[name] = collect(values(t_array)) -end - -reg_dict = Dict() -for dev in get_components(RegulationDevice, c_sys5_reg) - name = get_name(dev) - t_array = get_time_series_array( - Deterministic, - dev, - "max_active_power"; - start_time = DateTime("2024-01-01T00:00:00"), - ) - reg_dict[name] = collect(values(t_array)) -end - -remove_time_series!(c_sys5_reg, Deterministic) - -resolution = Dates.Hour(1) -dates = range(DateTime("2024-01-01T00:00:00"); step = resolution, length = 24) -c_sys5_reg - -for load in get_components(PowerLoad, c_sys5_reg) - name = get_name(load) - t_array = load_dict[name] - data = TimeArray(dates, t_array) - ts = SingleTimeSeries("max_active_power", data) - add_time_series!(c_sys5_reg, load, ts) -end - -for dev in get_components(RegulationDevice, c_sys5_reg) - name = get_name(dev) - t_array = reg_dict[name] - data = TimeArray(dates, t_array) - ts = SingleTimeSeries("max_active_power", data) - add_time_series!(c_sys5_reg, dev, ts) -end - -template_agc = template_agc_reserve_deployment() -model = EmulationModel(template_agc, c_sys5_reg; optimizer = Xpress.Optimizer) -build!(model; executions = 23, output_dir = mktempdir(; cleanup = true)) - -run!(model) From 290be5f870eea3aff67f43fca1ffd92fd2f147f4 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 1 Sep 2023 09:48:23 -0600 Subject: [PATCH 305/370] add formatter back --- scripts/formatter/Project.toml | 10 ++++++++++ scripts/formatter/formatter_code.jl | 28 ++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 scripts/formatter/Project.toml create mode 100644 scripts/formatter/formatter_code.jl diff --git a/scripts/formatter/Project.toml b/scripts/formatter/Project.toml new file mode 100644 index 0000000000..a33f747b58 --- /dev/null +++ b/scripts/formatter/Project.toml @@ -0,0 +1,10 @@ +uuid = "c6367ca8-164d-4469-afe3-c91cf8860505" +authors = ["Jose Daniel Lara "] + +[deps] +JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899" +Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" + +[compat] +JuliaFormatter = "1.0" +julia = "^1.7" diff --git a/scripts/formatter/formatter_code.jl b/scripts/formatter/formatter_code.jl new file mode 100644 index 0000000000..75bc991e6f --- /dev/null +++ b/scripts/formatter/formatter_code.jl @@ -0,0 +1,28 @@ +using Pkg +Pkg.activate(@__DIR__) +Pkg.instantiate() +Pkg.update() + +using JuliaFormatter + +main_paths = ["."] +for main_path in main_paths + for (root, dir, files) in walkdir(main_path) + for f in files + @show file_path = abspath(root, f) + !occursin(".jl", f) && continue + format(file_path; + whitespace_ops_in_indices = true, + remove_extra_newlines = true, + verbose = true, + always_for_in = true, + whitespace_typedefs = true, + conditional_to_if = true, + join_lines_based_on_source = true, + separate_kwargs_with_semicolon = true, + + # always_use_return = true. # Disabled since it throws a lot of false positives + ) + end + end +end From 945fa84ff1681df1359caa49676140ed24650e42 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 1 Sep 2023 09:53:23 -0600 Subject: [PATCH 306/370] run formatter --- test/test_services_constructor.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index f6aed68239..1c62b25f0d 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -353,7 +353,6 @@ end ServiceModel(ReserveDemandCurve{ReserveUp}, StepwiseCostReserve, "ORDC1"), ) - model = DecisionModel(template, c_sys5_uc) @test build!(model; output_dir = mktempdir(; cleanup = true)) == PSI.BuildStatus.BUILT moi_tests(model, 648, 0, 384, 216, 72, false) @@ -378,7 +377,7 @@ end participation_constraints = [ :ParticipationFractionConstraint__VariableReserve__ReserveUp__Reserve11, - :ParticipationFractionConstraint__VariableReserve__ReserveDown__Reserve2 + :ParticipationFractionConstraint__VariableReserve__ReserveDown__Reserve2, ] found_constraints = 0 From b7a6724e7db25c3dd394b0c43bef3143c8866e17 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 1 Sep 2023 10:47:33 -0600 Subject: [PATCH 307/370] add ff methods for slacks --- src/feedforward/feedforward_arguments.jl | 28 ++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/feedforward/feedforward_arguments.jl b/src/feedforward/feedforward_arguments.jl index adad3f4a18..f876c5bada 100644 --- a/src/feedforward/feedforward_arguments.jl +++ b/src/feedforward/feedforward_arguments.jl @@ -45,6 +45,34 @@ function _add_feedforward_arguments!( return end +function _add_feedforward_arguments!( + container::OptimizationContainer, + model::DeviceModel{T, U}, + devices::IS.FlattenIteratorWrapper{T}, + ff::V, +) where {T <: PSY.Device, U <: AbstractDeviceFormulation, V <: Union{LowerBoundFeedforward, UpperBoundFeedforward}} + parameter_type = get_default_parameter_type(ff, T) + add_parameters!(container, parameter_type, ff, model, devices) + if get_slacks(ff) + _add_slack_variable!(container, FeedForwardSlack(), ff, devices, U) + end + return +end + +function _add_feedforward_arguments!( + container::OptimizationContainer, + model::ServiceModel{SR}, + contributing_devices::Vector{T}, + ff::U, +) where {T <: PSY.Component, SR <: PSY.AbstractReserve, U <: Union{LowerBoundFeedforward, UpperBoundFeedforward}} + parameter_type = get_default_parameter_type(ff, SR) + add_parameters!(container, parameter_type, ff, model, contributing_devices) + if get_slacks(ff) + _add_slack_variable!(container, FeedForwardSlack(), ff, model, contributing_devices) + end + return +end + function _add_feedforward_arguments!( container::OptimizationContainer, model::DeviceModel, From 77a6685ad1a0c8ffad7e3275aa0d4586b0e80b93 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 1 Sep 2023 11:58:02 -0600 Subject: [PATCH 308/370] add slacks to feedforwards --- src/PowerSimulations.jl | 2 + src/core/variables.jl | 4 ++ src/feedforward/feedforward_arguments.jl | 60 +++++++++++++++++++----- src/feedforward/feedforwards.jl | 2 + test/test_services_constructor.jl | 1 - 5 files changed, 55 insertions(+), 14 deletions(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 82f3a32b7e..19d70f9ed8 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -234,6 +234,8 @@ export FlowReactivePowerFromToVariable export FlowReactivePowerToFromVariable export PowerAboveMinimumVariable export PhaseShifterAngle +export UpperBoundFeedForwardSlack +export LowerBoundFeedForwardSlack # Auxiliary variables export TimeDurationOn diff --git a/src/core/variables.jl b/src/core/variables.jl index 7141f4ee6c..8d04b12216 100644 --- a/src/core/variables.jl +++ b/src/core/variables.jl @@ -189,6 +189,10 @@ struct InterfaceFlowSlackUp <: VariableType end struct InterfaceFlowSlackDown <: VariableType end +struct UpperBoundFeedForwardSlack <: VariableType end + +struct LowerBoundFeedForwardSlack <: VariableType end + const START_VARIABLES = (HotStartVariable, WarmStartVariable, ColdStartVariable) should_write_resulting_value(::Type{<:VariableType}) = true diff --git a/src/feedforward/feedforward_arguments.jl b/src/feedforward/feedforward_arguments.jl index f876c5bada..a32a8db368 100644 --- a/src/feedforward/feedforward_arguments.jl +++ b/src/feedforward/feedforward_arguments.jl @@ -25,10 +25,10 @@ end function _add_feedforward_arguments!( container::OptimizationContainer, - model::DeviceModel, + model::DeviceModel{T, U}, devices::IS.FlattenIteratorWrapper{T}, ff::AbstractAffectFeedforward, -) where {T <: PSY.Component} +) where {T <: PSY.Device, U <: AbstractDeviceFormulation} parameter_type = get_default_parameter_type(ff, T) add_parameters!(container, parameter_type, ff, model, devices) return @@ -36,12 +36,40 @@ end function _add_feedforward_arguments!( container::OptimizationContainer, - model::ServiceModel{SR}, - contributing_devices::Vector{T}, + model::ServiceModel{T, U}, + contributing_devices::Vector, ff::AbstractAffectFeedforward, -) where {T <: PSY.Component, SR <: PSY.AbstractReserve} +) where {T <: PSY.AbstractReserve, U <: AbstractServiceFormulation} + parameter_type = get_default_parameter_type(ff, SR) + add_parameters!(container, parameter_type, ff, model, contributing_devices) + return +end + +function _add_feedforward_arguments!( + container::OptimizationContainer, + model::DeviceModel{T, U}, + devices::IS.FlattenIteratorWrapper{T}, + ff::UpperBoundFeedforward, +) where {T <: PSY.Device, U <: AbstractDeviceFormulation} + parameter_type = get_default_parameter_type(ff, T) + add_parameters!(container, parameter_type, ff, model, devices) + if get_slacks(ff) + add_variables!(container, UpperBoundFeedForwardSlack(), devices, U()) + end + return +end + +function _add_feedforward_arguments!( + container::OptimizationContainer, + model::ServiceModel{T, U}, + contributing_devices::Vector, + ff::UpperBoundFeedforward, +) where {T <: PSY.AbstractReserve, U <: AbstractServiceFormulation} parameter_type = get_default_parameter_type(ff, SR) add_parameters!(container, parameter_type, ff, model, contributing_devices) + if get_slacks(ff) + add_variables!(container, UpperBoundFeedForwardSlack(), contributing_devices, U()) + end return end @@ -49,12 +77,12 @@ function _add_feedforward_arguments!( container::OptimizationContainer, model::DeviceModel{T, U}, devices::IS.FlattenIteratorWrapper{T}, - ff::V, -) where {T <: PSY.Device, U <: AbstractDeviceFormulation, V <: Union{LowerBoundFeedforward, UpperBoundFeedforward}} + ff::LowerBoundFeedforward, +) where {T <: PSY.Device, U <: AbstractDeviceFormulation} parameter_type = get_default_parameter_type(ff, T) add_parameters!(container, parameter_type, ff, model, devices) if get_slacks(ff) - _add_slack_variable!(container, FeedForwardSlack(), ff, devices, U) + _add_slack_variable!(container, LowerBoundFeedForwardSlack(), devices, U) end return end @@ -63,22 +91,28 @@ function _add_feedforward_arguments!( container::OptimizationContainer, model::ServiceModel{SR}, contributing_devices::Vector{T}, - ff::U, -) where {T <: PSY.Component, SR <: PSY.AbstractReserve, U <: Union{LowerBoundFeedforward, UpperBoundFeedforward}} + ff::LowerBoundFeedforward, +) where {T <: PSY.Component, SR <: PSY.AbstractReserve} parameter_type = get_default_parameter_type(ff, SR) add_parameters!(container, parameter_type, ff, model, contributing_devices) if get_slacks(ff) - _add_slack_variable!(container, FeedForwardSlack(), ff, model, contributing_devices) + _add_slack_variable!( + container, + LowerBoundFeedForwardSlack(), + ff, + model, + contributing_devices, + ) end return end function _add_feedforward_arguments!( container::OptimizationContainer, - model::DeviceModel, + model::DeviceModel{T, U}, devices::IS.FlattenIteratorWrapper{T}, ff::SemiContinuousFeedforward, -) where {T <: PSY.Component} +) where {T <: PSY.Device, U <: AbstractDeviceFormulation} parameter_type = get_default_parameter_type(ff, T) add_parameters!(container, parameter_type, ff, model, devices) add_to_expression!( diff --git a/src/feedforward/feedforwards.jl b/src/feedforward/feedforwards.jl index 01c5c0492f..a6573e3d5e 100644 --- a/src/feedforward/feedforwards.jl +++ b/src/feedforward/feedforwards.jl @@ -83,6 +83,7 @@ end get_default_parameter_type(::UpperBoundFeedforward, _) = UpperBoundValueParameter get_optimization_container_key(ff::UpperBoundFeedforward) = ff.optimization_container_key +get_slacks(ff::UpperBoundFeedforward) = ff.add_slacks """ Adds a lower bound constraint to a variable. @@ -119,6 +120,7 @@ end get_default_parameter_type(::LowerBoundFeedforward, _) = LowerBoundValueParameter get_optimization_container_key(ff::LowerBoundFeedforward) = ff.optimization_container_key +get_slacks(ff::LowerBoundFeedforward) = ff.add_slacks """ Adds a constraint to make the bounds of a variable 0.0. Effectively allows to "turn off" a value. diff --git a/test/test_services_constructor.jl b/test/test_services_constructor.jl index 1c62b25f0d..28bc99ac2e 100644 --- a/test/test_services_constructor.jl +++ b/test/test_services_constructor.jl @@ -364,7 +364,6 @@ end ] found_vars = 0 for (k, var_array) in model.internal.container.variables - @show PSI.encode_key(k) if PSI.encode_key(k) in reserve_variables for var in var_array @test JuMP.has_lower_bound(var) From 3738c7b591c02b34d5a9a4d4c8b5ebee68784ac4 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 1 Sep 2023 17:30:32 -0600 Subject: [PATCH 309/370] implement ff correctly for services --- src/feedforward/feedforward_arguments.jl | 109 +++++++++++++++++++-- src/feedforward/feedforward_constraints.jl | 55 ++++++++--- src/feedforward/feedforwards.jl | 25 +++++ src/parameters/update_parameters.jl | 44 ++++++++- src/utils/jump_utils.jl | 2 +- 5 files changed, 210 insertions(+), 25 deletions(-) diff --git a/src/feedforward/feedforward_arguments.jl b/src/feedforward/feedforward_arguments.jl index a32a8db368..ea85b62627 100644 --- a/src/feedforward/feedforward_arguments.jl +++ b/src/feedforward/feedforward_arguments.jl @@ -45,6 +45,83 @@ function _add_feedforward_arguments!( return end +function _add_feedforward_slack_variables!(container::OptimizationContainer, + ::T, + ff::Union{LowerBoundFeedforward, UpperBoundFeedforward}, + model::ServiceModel{U, V}, + devices::Vector, +) where { + T <: Union{LowerBoundFeedForwardSlack, UpperBoundFeedForwardSlack}, + U <: PSY.AbstractReserve, + V <: AbstractReservesFormulation, +} + time_steps = get_time_steps(container) + for var in get_affected_values(ff) + variable = get_variable(container, var) + set_name, set_time = JuMP.axes(variable) + device_names = [PSY.get_name(d) for d in devices] + IS.@assert_op set_name == device_names + IS.@assert_op set_time == time_steps + service_name = get_service_name(model) + var_type = get_entry_type(var) + variable_container = add_variable_container!( + container, + T(), + U, + device_names, + time_steps; + meta = "$(var_type)_$(service_name)", + ) + + for t in time_steps, name in set_name + variable_container[name, t] = JuMP.@variable( + get_jump_model(container), + base_name = "$(T)_$(U)_{$(name), $(t)}", + lower_bound = 0.0 + ) + end + end + return +end + +function _add_feedforward_slack_variables!( + container::OptimizationContainer, + ::T, + ff::Union{LowerBoundFeedforward, UpperBoundFeedforward}, + model::DeviceModel{U, V}, + devices::IS.FlattenIteratorWrapper{U}, +) where { + T <: Union{LowerBoundFeedForwardSlack, UpperBoundFeedForwardSlack}, + U <: PSY.Device, + V <: AbstractDeviceFormulation, +} + time_steps = get_time_steps(container) + for var in get_affected_values(ff) + variable = get_variable(container, var) + set_name, set_time = JuMP.axes(variable) + IS.@assert_op set_name == [PSY.get_name(d) for d in devices] + IS.@assert_op set_time == time_steps + + var_type = get_entry_type(var) + variable = add_variable_container!( + container, + T, + U, + [PSY.get_name(d) for d in devices]; + meta = "$(var_type)", + ) + + for t in time_steps, name in set_name + variable[name, t] = JuMP.@variable( + get_jump_model(container), + base_name = "$(T)_$(U)_{$(name), $(t)}", + lower_bound = 0.0 + ) + end + end + return +end + function _add_feedforward_arguments!( container::OptimizationContainer, model::DeviceModel{T, U}, @@ -54,7 +131,12 @@ function _add_feedforward_arguments!( parameter_type = get_default_parameter_type(ff, T) add_parameters!(container, parameter_type, ff, model, devices) if get_slacks(ff) - add_variables!(container, UpperBoundFeedForwardSlack(), devices, U()) + add_feedforward_slack_variables!( + container, + UpperBoundFeedForwardSlack, + devices, + model, + ) end return end @@ -68,7 +150,12 @@ function _add_feedforward_arguments!( parameter_type = get_default_parameter_type(ff, SR) add_parameters!(container, parameter_type, ff, model, contributing_devices) if get_slacks(ff) - add_variables!(container, UpperBoundFeedForwardSlack(), contributing_devices, U()) + add_feedforward_slack_variables!( + container, + UpperBoundFeedForwardSlack, + contributing_devices, + model, + ) end return end @@ -82,21 +169,27 @@ function _add_feedforward_arguments!( parameter_type = get_default_parameter_type(ff, T) add_parameters!(container, parameter_type, ff, model, devices) if get_slacks(ff) - _add_slack_variable!(container, LowerBoundFeedForwardSlack(), devices, U) + _add_feedforward_slack_variables!( + container, + LowerBoundFeedForwardSlack, + ff, + model, + devices, + ) end return end function _add_feedforward_arguments!( container::OptimizationContainer, - model::ServiceModel{SR}, - contributing_devices::Vector{T}, + model::ServiceModel{T, U}, + contributing_devices::Vector{V}, ff::LowerBoundFeedforward, -) where {T <: PSY.Component, SR <: PSY.AbstractReserve} - parameter_type = get_default_parameter_type(ff, SR) +) where {T <: PSY.AbstractReserve, U <: AbstractReservesFormulation, V <: PSY.Component} + parameter_type = get_default_parameter_type(ff, T) add_parameters!(container, parameter_type, ff, model, contributing_devices) if get_slacks(ff) - _add_slack_variable!( + _add_feedforward_slack_variables!( container, LowerBoundFeedForwardSlack(), ff, diff --git a/src/feedforward/feedforward_constraints.jl b/src/feedforward/feedforward_constraints.jl index 3c31c8e6bc..8c4bf19bfa 100644 --- a/src/feedforward/feedforward_constraints.jl +++ b/src/feedforward/feedforward_constraints.jl @@ -319,10 +319,10 @@ The Parameters are initialized using the uppper boundary values of the provided """ function add_feedforward_constraints!( container::OptimizationContainer, - ::DeviceModel, + ::DeviceModel{T, U}, devices::IS.FlattenIteratorWrapper{T}, ff::LowerBoundFeedforward, -) where {T <: PSY.Component} +) where {T <: PSY.Component, U <: AbstractDeviceFormulation} time_steps = get_time_steps(container) parameter_type = get_default_parameter_type(ff, T) param_ub = get_parameter_array(container, parameter_type(), T) @@ -344,10 +344,20 @@ function add_feedforward_constraints!( ) for t in time_steps, name in set_name - con_ub[name, t] = JuMP.@constraint( - container.JuMPmodel, - variable[name, t] >= param_ub[name, t] * multiplier_ub[name, t] - ) + if use_slacks + slack_var = + get_variable(container, LowerBoundFeedForwardSlack(), T, "$(var_type)") + con_ub[name, t] = JuMP.@constraint( + get_jump_model(container), + variable[name, t] >= + param_ub[name, t] * multiplier_ub[name, t] + slack_var[name, t] + ) + else + con_ub[name, t] = JuMP.@constraint( + get_jump_model(container), + variable[name, t] >= param_ub[name, t] * multiplier_ub[name, t] + ) + end end end return @@ -358,16 +368,18 @@ function add_feedforward_constraints!( model::ServiceModel{T, U}, contributing_devices::Vector{V}, ff::LowerBoundFeedforward, -) where {T, U, V <: PSY.Component} +) where {T <: PSY.Service, U <: AbstractServiceFormulation, V <: PSY.Component} time_steps = get_time_steps(container) parameter_type = get_default_parameter_type(ff, T) param_ub = get_parameter_array(container, parameter_type(), T, get_service_name(model)) + service_name = get_service_name(model) multiplier_ub = get_parameter_multiplier_array( container, parameter_type(), T, - get_service_name(model), + service_name, ) + use_slacks = get_slacks(ff) for var in get_affected_values(ff) variable = get_variable(container, var) set_name, set_time = JuMP.axes(variable) @@ -375,20 +387,35 @@ function add_feedforward_constraints!( IS.@assert_op set_time == time_steps var_type = get_entry_type(var) - con_ub = add_constraints_container!( + con_lb = add_constraints_container!( container, FeedforwardLowerBoundConstraint(), T, set_name, time_steps; - meta = "$(var_type)lb", + meta = "$(var_type)_$(service_name)", ) for t in time_steps, name in set_name - con_ub[name, t] = JuMP.@constraint( - container.JuMPmodel, - variable[name, t] >= param_ub[name, t] * multiplier_ub[name, t] - ) + if use_slacks + slack_var = get_variable( + container, + LowerBoundFeedForwardSlack(), + T, + "$(var_type)_$(service_name)", + ) + slack_var[name, t] + con_lb[name, t] = JuMP.@constraint( + get_jump_model(container), + variable[name, t] >= + param_ub[name, t] * multiplier_ub[name, t] + slack_var[name, t] + ) + else + con_lb[name, t] = JuMP.@constraint( + get_jump_model(container), + variable[name, t] >= param_ub[name, t] * multiplier_ub[name, t] + ) + end end end return diff --git a/src/feedforward/feedforwards.jl b/src/feedforward/feedforwards.jl index a6573e3d5e..a5f3bb4729 100644 --- a/src/feedforward/feedforwards.jl +++ b/src/feedforward/feedforwards.jl @@ -122,6 +122,31 @@ get_default_parameter_type(::LowerBoundFeedforward, _) = LowerBoundValueParamete get_optimization_container_key(ff::LowerBoundFeedforward) = ff.optimization_container_key get_slacks(ff::LowerBoundFeedforward) = ff.add_slacks +function attach_feedforward!( + model::ServiceModel, + ff::T, +) where {T <: Union{LowerBoundFeedforward, UpperBoundFeedforward}} + if get_feedforward_meta(ff) != NO_SERVICE_NAME_PROVIDED + ff_ = ff + else + ff_ = T(; + component_type = get_component_type(ff), + source = get_entry_type(get_optimization_container_key(ff)), + affected_values = [get_entry_type(get_optimization_container_key(ff))], + meta = model.service_name, + add_slacks = ff.add_slacks, + ) + end + if !isempty(model.feedforwards) + ff_k = [get_optimization_container_key(v) for v in model.feedforwards if isa(v, T)] + if get_optimization_container_key(ff_) ∈ ff_k + return + end + end + push!(model.feedforwards, ff_) + return +end + """ Adds a constraint to make the bounds of a variable 0.0. Effectively allows to "turn off" a value. """ diff --git a/src/parameters/update_parameters.jl b/src/parameters/update_parameters.jl index 800ff88ebc..a9c738087b 100644 --- a/src/parameters/update_parameters.jl +++ b/src/parameters/update_parameters.jl @@ -164,7 +164,47 @@ end function _update_parameter_values!( parameter_array::AbstractArray{T}, attributes::VariableValueAttributes, - ::Type{<:PSY.Component}, + ::Type{<:PSY.Device}, + model::DecisionModel, + state::DatasetContainer{InMemoryDataset}, +) where {T <: Union{JuMP.VariableRef, Float64}} + current_time = get_current_time(model) + state_values = get_dataset_values(state, get_attribute_key(attributes)) + component_names, time = axes(parameter_array) + resolution = get_resolution(model) + + state_data = get_dataset(state, get_attribute_key(attributes)) + state_timestamps = state_data.timestamps + max_state_index = get_num_rows(state_data) + + state_data_index = find_timestamp_index(state_timestamps, current_time) + sim_timestamps = range(current_time; step = resolution, length = time[end]) + for t in time + timestamp_ix = min(max_state_index, state_data_index + 1) + @debug "parameter horizon is over the step" max_state_index > state_data_index + 1 + if state_timestamps[timestamp_ix] <= sim_timestamps[t] + state_data_index = timestamp_ix + end + for name in component_names + # Pass indices in this way since JuMP DenseAxisArray don't support view() + state_value = state_values[name, state_data_index] + if !isfinite(state_value) + error( + "The value for the system state used in $(encode_key_as_string(get_attribute_key(attributes))) is not a finite value $(state_value) \ + This is commonly caused by referencing a state value at a time when such decision hasn't been made. \ + Consider reviewing your models' horizon and interval definitions", + ) + end + _set_param_value!(parameter_array, state_value, name, t) + end + end + return +end + +function _update_parameter_values!( + parameter_array::AbstractArray{T}, + attributes::VariableValueAttributes, + ::PSY.Reserve, model::DecisionModel, state::DatasetContainer{InMemoryDataset}, ) where {T <: Union{JuMP.VariableRef, Float64}} @@ -207,7 +247,7 @@ function _update_parameter_values!( ::Type{U}, model::DecisionModel, state::DatasetContainer{InMemoryDataset}, -) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.Component} +) where {T <: Union{JuMP.VariableRef, Float64}, U <: PSY.Device} current_time = get_current_time(model) state_values = get_dataset_values(state, get_attribute_key(attributes)) component_names, time = axes(parameter_array) diff --git a/src/utils/jump_utils.jl b/src/utils/jump_utils.jl index 22ee166e56..187aa7b3e7 100644 --- a/src/utils/jump_utils.jl +++ b/src/utils/jump_utils.jl @@ -1,6 +1,6 @@ #Given the changes in syntax in ParameterJuMP and the new format to create anonymous parameters function add_jump_parameter(jump_model::JuMP.Model, val::Number) - param = JuMP.@variable(jump_model) + param = JuMP.@variable(jump_model, base_name = "param") JuMP.fix(param, val; force = true) return param end From 68f8e08f8a022f46a5ee77ff08818b12e925d71b Mon Sep 17 00:00:00 2001 From: alefcastelli Date: Tue, 5 Sep 2023 09:25:35 -0600 Subject: [PATCH 310/370] removed error due to the presence of multiple reference buses. The model was tested and it works. --- src/core/network_model.jl | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/core/network_model.jl b/src/core/network_model.jl index 923e9c735b..4cce44d90e 100644 --- a/src/core/network_model.jl +++ b/src/core/network_model.jl @@ -69,12 +69,6 @@ function instantiate_network_model( if isempty(model.subnetworks) model.subnetworks = PNM.find_subnetworks(sys) end - - if length(model.subnetworks) > 1 - error( - "System Contains Multiple Subnetworks. This is not compatible with network model $T", - ) - end return end From 94e481081295ba67063b807cf3a51cf5dc13fb6f Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 5 Sep 2023 11:10:01 -0600 Subject: [PATCH 311/370] add FF slack to objective function --- src/feedforward/feedforward_arguments.jl | 5 +++++ test/test_basic_model_structs.jl | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/feedforward/feedforward_arguments.jl b/src/feedforward/feedforward_arguments.jl index ea85b62627..520fc5f8fb 100644 --- a/src/feedforward/feedforward_arguments.jl +++ b/src/feedforward/feedforward_arguments.jl @@ -79,7 +79,12 @@ function _add_feedforward_slack_variables!(container::OptimizationContainer, base_name = "$(T)_$(U)_{$(name), $(t)}", lower_bound = 0.0 ) + add_to_objective_invariant_expression!( + container, + variable_container[name, t] * BALANCE_SLACK_COST, + ) end + end return end diff --git a/test/test_basic_model_structs.jl b/test/test_basic_model_structs.jl index 6928b5e196..e456761b9f 100644 --- a/test/test_basic_model_structs.jl +++ b/test/test_basic_model_structs.jl @@ -69,12 +69,14 @@ end component_type = RenewableDispatch, source = ActivePowerVariable, affected_values = [OnStatusParameter], + use_slacks = true, ) @test_throws ErrorException LowerBoundFeedforward( component_type = RenewableDispatch, source = ActivePowerVariable, affected_values = [OnStatusParameter], + use_slacks = true, ) @test_throws ErrorException SemiContinuousFeedforward( From 3e8da3b3f46a6347a01fa6921ce32589eee642b6 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 5 Sep 2023 11:12:05 -0600 Subject: [PATCH 312/370] formatter --- src/feedforward/feedforward_arguments.jl | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/feedforward/feedforward_arguments.jl b/src/feedforward/feedforward_arguments.jl index 520fc5f8fb..abfadf8214 100644 --- a/src/feedforward/feedforward_arguments.jl +++ b/src/feedforward/feedforward_arguments.jl @@ -80,11 +80,10 @@ function _add_feedforward_slack_variables!(container::OptimizationContainer, lower_bound = 0.0 ) add_to_objective_invariant_expression!( - container, - variable_container[name, t] * BALANCE_SLACK_COST, - ) + container, + variable_container[name, t] * BALANCE_SLACK_COST, + ) end - end return end From 5dd814213e543a80a08ae459e463307f69d6779d Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 5 Sep 2023 11:26:10 -0600 Subject: [PATCH 313/370] fix sign --- src/feedforward/feedforward_constraints.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/feedforward/feedforward_constraints.jl b/src/feedforward/feedforward_constraints.jl index 8c4bf19bfa..f7b3b798df 100644 --- a/src/feedforward/feedforward_constraints.jl +++ b/src/feedforward/feedforward_constraints.jl @@ -349,8 +349,8 @@ function add_feedforward_constraints!( get_variable(container, LowerBoundFeedForwardSlack(), T, "$(var_type)") con_ub[name, t] = JuMP.@constraint( get_jump_model(container), - variable[name, t] >= - param_ub[name, t] * multiplier_ub[name, t] + slack_var[name, t] + variable[name, t] + slack_var[name, t] >= + param_ub[name, t] * multiplier_ub[name, t] ) else con_ub[name, t] = JuMP.@constraint( @@ -407,8 +407,8 @@ function add_feedforward_constraints!( slack_var[name, t] con_lb[name, t] = JuMP.@constraint( get_jump_model(container), - variable[name, t] >= - param_ub[name, t] * multiplier_ub[name, t] + slack_var[name, t] + variable[name, t] + slack_var[name, t] >= + param_ub[name, t] * multiplier_ub[name, t] ) else con_lb[name, t] = JuMP.@constraint( From 8b1c7e6005a4843b87550aac38f375f9f1db605b Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 5 Sep 2023 12:22:53 -0600 Subject: [PATCH 314/370] fix tests --- test/test_basic_model_structs.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/test_basic_model_structs.jl b/test/test_basic_model_structs.jl index e456761b9f..b33431ca31 100644 --- a/test/test_basic_model_structs.jl +++ b/test/test_basic_model_structs.jl @@ -23,11 +23,13 @@ end component_type = RenewableDispatch, source = ActivePowerVariable, affected_values = [ActivePowerVariable], + add_slacks = true, ), LowerBoundFeedforward(; component_type = RenewableDispatch, source = ActivePowerVariable, affected_values = [ActivePowerVariable], + add_slacks = true, ), SemiContinuousFeedforward(; component_type = ThermalMultiStart, @@ -69,14 +71,14 @@ end component_type = RenewableDispatch, source = ActivePowerVariable, affected_values = [OnStatusParameter], - use_slacks = true, + add_slacks = true, ) @test_throws ErrorException LowerBoundFeedforward( component_type = RenewableDispatch, source = ActivePowerVariable, affected_values = [OnStatusParameter], - use_slacks = true, + add_slacks = true, ) @test_throws ErrorException SemiContinuousFeedforward( From 9d0a0fd839da4cc4713f69f96e3b8138d0c0c3a1 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 5 Sep 2023 13:14:28 -0600 Subject: [PATCH 315/370] Update Project.toml --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index e0a105f6ce..d6ecd2ebe1 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "PowerSimulations" uuid = "e690365d-45e2-57bb-ac84-44ba829e73c4" authors = ["Jose Daniel Lara", "Clayton Barrows", "Daniel Thom", "Dheepak Krishnamurthy", "Sourabh Dalvi"] -version = "0.21.3" +version = "0.21.4" [deps] CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" From 98abfc649f10cce08c00ec4a982df0c94879ffeb Mon Sep 17 00:00:00 2001 From: Barrows Date: Wed, 19 Jul 2023 13:05:53 -0400 Subject: [PATCH 316/370] adding missing stuff --- docs/Project.toml | 1 + src/core/parameters.jl | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/docs/Project.toml b/docs/Project.toml index 93b8458786..db78f98971 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -6,6 +6,7 @@ DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" DocumenterTools = "35a29f4d-8980-5a13-9543-d66fff28ecb8" GLPK = "60bf3e95-4087-53dc-ae20-288a0d20c6a6" +HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b" InfrastructureSystems = "2cd47ed4-ca9b-11e9-27f2-ab636a7671f1" Latexify = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" PowerSimulations = "e690365d-45e2-57bb-ac84-44ba829e73c4" diff --git a/src/core/parameters.jl b/src/core/parameters.jl index 2e7975a430..58aa0322a6 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -303,13 +303,40 @@ struct OutflowTimeSeriesParameter <: TimeSeriesParameter end abstract type VariableValueParameter <: RightHandSideParameter end +""" +Parameter to define variable upper bound +""" struct UpperBoundValueParameter <: VariableValueParameter end + +""" +Parameter to define variable lower bound +""" struct LowerBoundValueParameter <: VariableValueParameter end + +""" +Parameter to define unit commitment status +""" struct OnStatusParameter <: VariableValueParameter end + +""" +Parameter to define energy limit +""" struct EnergyLimitParameter <: VariableValueParameter end + +""" +Parameter to define fixed output values +""" struct FixValueParameter <: VariableValueParameter end + + +""" +Parameter to define energy storage target +""" struct EnergyTargetParameter <: VariableValueParameter end +""" +Parameter to define cost function coefficient +""" struct CostFunctionParameter <: ObjectiveFunctionParameter end abstract type AuxVariableValueParameter <: RightHandSideParameter end From 7d64ce725dce521e149e9e66b994be4150ac1a75 Mon Sep 17 00:00:00 2001 From: Barrows Date: Wed, 19 Jul 2023 13:06:04 -0400 Subject: [PATCH 317/370] fixing hydro uc form --- docs/src/formulation_library/HydroGen.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md index efe13982b3..29704805f8 100644 --- a/docs/src/formulation_library/HydroGen.md +++ b/docs/src/formulation_library/HydroGen.md @@ -125,7 +125,7 @@ Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance ```math \begin{aligned} -& Pg_t \le Pg^\text{max}\\ +& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ & Pg_t - u_t Pg^\text{max} \le 0 \\ & Pg_t - u_t Pg^\text{min} \ge 0 \\ & Qg_t - u_t Qg^\text{max} \le 0 \\ From 538c6035efa535f72a7810fc36055aab19c1bb54 Mon Sep 17 00:00:00 2001 From: Clayton Barrows Date: Wed, 19 Jul 2023 13:39:49 -0400 Subject: [PATCH 318/370] Update src/core/parameters.jl Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- src/core/parameters.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index 58aa0322a6..d20f0b40e4 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -328,7 +328,6 @@ Parameter to define fixed output values """ struct FixValueParameter <: VariableValueParameter end - """ Parameter to define energy storage target """ From f2e36cf854cf8b96206a1b51001918c7971f7d8b Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 10 Jul 2023 17:27:17 -0600 Subject: [PATCH 319/370] create new model types --- docs/src/get_test_data.jl | 2 +- src/PowerSimulations.jl | 7 ++- src/core/optimization_container.jl | 6 ++- src/operation/decision_model.jl | 54 +++++++++++++++++--- src/operation/emulation_model.jl | 52 +++++++++++++++++-- src/operation/operation_model_interface.jl | 14 ++--- src/operation/operation_problem_templates.jl | 6 +-- src/operation/problem_template.jl | 12 +++++ test/test_utils/mock_operation_models.jl | 6 +-- 9 files changed, 126 insertions(+), 33 deletions(-) diff --git a/docs/src/get_test_data.jl b/docs/src/get_test_data.jl index 79e9e0acf3..2c99e65808 100644 --- a/docs/src/get_test_data.jl +++ b/docs/src/get_test_data.jl @@ -9,7 +9,7 @@ const PSY = PowerSystems include("../../../test/test_utils/get_test_data.jl") -abstract type TestOpProblem <: PSI.DecisionProblem end +abstract type TestOpProblem <: PSI.DefaultDecisionProblem end system = build_c_sys5_re(; add_reserves = true) solver = optimizer_with_attributes(Cbc.Optimizer) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 19d70f9ed8..5b6b431b30 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -372,6 +372,7 @@ import Distributed # Base Imports import Base.getindex +import Base.isempty import Base.length import Base.first import InteractiveUtils: methodswith @@ -457,13 +458,11 @@ include("core/dataset.jl") include("core/dataset_container.jl") include("core/results_by_time.jl") +# Order Required +include("operation/problem_template.jl") include("core/optimization_container.jl") include("core/store_common.jl") - -# Order Required include("initial_conditions/initial_condition_chronologies.jl") - -include("operation/problem_template.jl") include("operation/operation_model_interface.jl") include("operation/model_store_params.jl") include("operation/abstract_model_store.jl") diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index 0e03fc33fa..3cdff305be 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -475,7 +475,11 @@ function initialize_system_expressions!( return end -function build_impl!(container::OptimizationContainer, template, sys::PSY.System) +function build_impl!( + container::OptimizationContainer, + template::ProblemTemplate, + sys::PSY.System, +) transmission = get_network_formulation(template) transmission_model = get_network_model(template) initialize_system_expressions!(container, transmission, transmission_model.subnetworks) diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index 623aab96db..be7e112603 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -1,7 +1,13 @@ """ -Default PowerSimulations Operation Problem Type +Abstract type for models than employ PowerSimulations methods. For custom decision problems + use DecisionProblem as the super type. """ -struct GenericOpProblem <: DecisionProblem end +abstract type DefaultDecisionProblem <: DecisionProblem end + +""" +Generic PowerSimulations Operation Problem Type for unspecified models +""" +struct GenericOpProblem <: DefaultDecisionProblem end """ DecisionModel{M}( @@ -10,7 +16,7 @@ struct GenericOpProblem <: DecisionProblem end jump_model::Union{Nothing, JuMP.Model}=nothing; kwargs...) where {M<:DecisionProblem} -This builds the optimization problem of type M with the specific system and template. +Builds the optimization problem of type M with the specific system and template. # Arguments @@ -136,7 +142,7 @@ function DecisionModel{M}( end """ -This builds the optimization problem of type M with the specific system and template +Builds the optimization problem of type M with the specific system and template # Arguments @@ -171,6 +177,30 @@ function DecisionModel( return DecisionModel{GenericOpProblem}(template, sys, jump_model; kwargs...) end +""" +Builds an empty decision model. This constructor is used for the implementation of custom +decision models that do not require a template. + +# Arguments + + - `::Type{M} where M<:DecisionProblem`: The abstract operation model type + - `sys::PSY.System`: 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 = DecisionModel(system, optimizer) +``` +""" +function DecisionModel{M}( + sys::PSY.System, + jump_model::Union{Nothing, JuMP.Model} = nothing; + kwargs..., +) where {M <: DecisionProblem} + return DecisionModel{M}(ProblemTemplate(), sys, jump_model; kwargs...) +end + """ Construct an DecisionProblem from a serialized file. @@ -200,6 +230,9 @@ function DecisionModel( ) end +get_problem_type(::DecisionModel{M}) where {M <: DecisionProblem} = M +validate_template(::DecisionModel{<:DecisionProblem}) = nothing + # Probably could be more efficient by storing the info in the internal function get_current_time(model::DecisionModel) execution_count = get_internal(model).execution_count @@ -228,9 +261,9 @@ function init_model_store_params!(model::DecisionModel) return end -function build_pre_step!(model::DecisionModel) +function build_pre_step!(model::DecisionModel{<:DefaultDecisionProblem}) TimerOutputs.@timeit BUILD_PROBLEMS_TIMER "Build pre-step" begin - if !is_empty(model) + if !isempty(model) @info "OptimizationProblem status not BuildStatus.EMPTY. Resetting" reset!(model) end @@ -254,6 +287,15 @@ function build_pre_step!(model::DecisionModel) return end +function build_impl!(model::DecisionModel{<:DefaultDecisionProblem}) + validate_template(model) + build_pre_step!(model) + build_model!(model) + serialize_metadata!(get_optimization_container(model), get_output_dir(model)) + log_values(get_settings(model)) + return +end + get_horizon(model::DecisionModel) = get_horizon(get_settings(model)) """ diff --git a/src/operation/emulation_model.jl b/src/operation/emulation_model.jl index 724134c344..f3e60c9d48 100644 --- a/src/operation/emulation_model.jl +++ b/src/operation/emulation_model.jl @@ -1,7 +1,13 @@ """ -Default PowerSimulations Emulation Problem Type +Abstract type for models than employ PowerSimulations methods. For custom emulation problems + use EmulationProblem as the super type. """ -struct GenericEmulationProblem <: EmulationProblem end +abstract type DefaultEmulationProblem <: EmulationProblem end + +""" +Default PowerSimulations Emulation Problem Type for unspecified problems +""" +struct GenericEmulationProblem <: DefaultEmulationProblem end """ EmulationModel{M}( @@ -10,7 +16,7 @@ struct GenericEmulationProblem <: EmulationProblem end jump_model::Union{Nothing, JuMP.Model}=nothing; kwargs...) where {M<:EmulationProblem} -This builds the optimization problem of type M with the specific system and template. +Builds the optimization problem of type M with the specific system and template. # Arguments @@ -126,7 +132,7 @@ function EmulationModel{M}( end """ -This builds the optimization problem of type M with the specific system and template +Builds the optimization problem of type M with the specific system and template # Arguments @@ -162,6 +168,30 @@ function EmulationModel( 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::PSY.System`: 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::PSY.System, + jump_model::Union{Nothing, JuMP.Model} = nothing; + kwargs..., +) where {M <: EmulationProblem} + return EmulationModel{M}(template, sys, jump_model; kwargs...) +end + """ Construct an EmulationProblem from a serialized file. @@ -192,6 +222,9 @@ function EmulationModel( ) end +get_problem_type(::EmulationModel{M}) where {M <: EmulationProblem} = M +validate_template(::EmulationModel{<:EmulationProblem}) = nothing + function get_current_time(model::EmulationModel) execution_count = get_internal(model).execution_count initial_time = get_initial_time(model) @@ -219,7 +252,7 @@ end function build_pre_step!(model::EmulationModel) TimerOutputs.@timeit BUILD_PROBLEMS_TIMER "Build pre-step" begin - if !is_empty(model) + if !isempty(model) @info "EmulationProblem status not BuildStatus.EMPTY. Resetting" reset!(model) end @@ -243,6 +276,15 @@ function build_pre_step!(model::EmulationModel) return end +function build_impl!(model::EmulationModel{<:DefaultEmulationProblem}) + validate_template(model) + build_pre_step!(model) + build_model!(model) + serialize_metadata!(get_optimization_container(model), get_output_dir(model)) + log_values(get_settings(model)) + return +end + """ Implementation of build for any EmulationProblem """ diff --git a/src/operation/operation_model_interface.jl b/src/operation/operation_model_interface.jl index fb2b302e5b..bb925f4441 100644 --- a/src/operation/operation_model_interface.jl +++ b/src/operation/operation_model_interface.jl @@ -1,6 +1,6 @@ # Default implementations of getter/setter functions for OperationModel. is_built(model::OperationModel) = model.internal.status == BuildStatus.BUILT -is_empty(model::OperationModel) = model.internal.status == BuildStatus.EMPTY +isempty(model::OperationModel) = model.internal.status == BuildStatus.EMPTY warm_start_enabled(model::OperationModel) = get_warm_start(get_optimization_container(model).settings) built_for_recurrent_solves(model::OperationModel) = @@ -213,6 +213,9 @@ end function validate_template(model::OperationModel) template = get_template(model) + if isempty(template) + error("Template can't be empty for models $(get_problem_type(model))") + end modeled_types = get_component_types(template) system = get_system(model) system_component_types = PSY.get_existing_component_types(system) @@ -228,15 +231,6 @@ function validate_template(model::OperationModel) return end -function build_impl!(model::OperationModel) - validate_template(model) - build_pre_step!(model) - build_model!(model) - serialize_metadata!(get_optimization_container(model), get_output_dir(model)) - log_values(get_settings(model)) - return -end - function build_if_not_already_built!(model; kwargs...) status = get_status(model) if status == BuildStatus.EMPTY diff --git a/src/operation/operation_problem_templates.jl b/src/operation/operation_problem_templates.jl index 5a60c03c52..fb6a1f9206 100644 --- a/src/operation/operation_problem_templates.jl +++ b/src/operation/operation_problem_templates.jl @@ -1,7 +1,7 @@ -struct EconomicDispatchProblem <: DecisionProblem end -struct UnitCommitmentProblem <: DecisionProblem end -struct AGCReserveDeployment <: DecisionProblem end +struct EconomicDispatchProblem <: DefaultDecisionProblem end +struct UnitCommitmentProblem <: DefaultDecisionProblem end +struct AGCReserveDeployment <: DefaultDecisionProblem end function _default_devices_uc() return [ diff --git a/src/operation/problem_template.jl b/src/operation/problem_template.jl index 92e86e8fc5..eca8246cde 100644 --- a/src/operation/problem_template.jl +++ b/src/operation/problem_template.jl @@ -31,6 +31,18 @@ mutable struct ProblemTemplate end end +function Base.isempty(template::ProblemTemplate) + if !isempty(template.devices) + return false + elseif !isempty(template.branches) + return false + elseif !isempty(template.services) + return false + else + return true + end +end + ProblemTemplate(::Type{T}) where {T <: PM.AbstractPowerModel} = ProblemTemplate(NetworkModel(T)) ProblemTemplate() = ProblemTemplate(CopperPlatePowerModel) diff --git a/test/test_utils/mock_operation_models.jl b/test/test_utils/mock_operation_models.jl index 4f00ac010f..49b276d237 100644 --- a/test/test_utils/mock_operation_models.jl +++ b/test/test_utils/mock_operation_models.jl @@ -1,8 +1,8 @@ # NOTE: None of the models and function in this file are functional. All of these are used for testing purposes and do not represent valid examples either to develop custom # models. Please refer to the documentation. -struct MockOperationProblem <: PSI.DecisionProblem end -struct MockEmulationProblem <: PSI.EmulationProblem end +struct MockOperationProblem <: PSI.DefaultDecisionProblem end +struct MockEmulationProblem <: PSI.DefaultEmulationProblem end function PSI.DecisionModel( ::Type{MockOperationProblem}, @@ -194,7 +194,7 @@ end function setup_ic_model_container!(model::DecisionModel) # This function is only for testing purposes. - if !PSI.is_empty(model) + if !PSI.isempty(model) PSI.reset!(model) end From 1e4f639723902bd02b4dd09b819e15b96c9f1adb Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 10 Jul 2023 20:47:28 -0600 Subject: [PATCH 320/370] additional updates to build custom models --- src/operation/decision_model.jl | 47 ++++++++----- src/operation/decision_model_store.jl | 4 ++ src/operation/emulation_model.jl | 29 +++++--- src/operation/operation_model_interface.jl | 79 ++++++++++++---------- 4 files changed, 95 insertions(+), 64 deletions(-) diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index be7e112603..9dbfc499a1 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -71,12 +71,6 @@ mutable struct DecisionModel{M <: DecisionProblem} <: OperationModel elseif name isa String name = Symbol(name) end - _, _, forecast_count = PSY.get_time_series_counts(sys) - if forecast_count < 1 - error( - "The system does not contain forecast data. A DecisionModel can't be built.", - ) - end internal = ModelInternal( OptimizationContainer(sys, settings, jump_model, PSY.Deterministic), ) @@ -201,6 +195,16 @@ function DecisionModel{M}( return DecisionModel{M}(ProblemTemplate(), sys, jump_model; kwargs...) end +function DecisionModel{M}( + sys::PSY.System, + jump_model::Union{Nothing, JuMP.Model} = nothing; + kwargs..., +) where {M <: DefaultDecisionProblem} + IS.ArgumentError( + "DefaultDecisionProblem subtypes require a template. Use DecisionModel subtyping instead.", + ) +end + """ Construct an DecisionProblem from a serialized file. @@ -232,6 +236,7 @@ end get_problem_type(::DecisionModel{M}) where {M <: DecisionProblem} = M validate_template(::DecisionModel{<:DecisionProblem}) = nothing +validate_time_series(::DecisionModel{<:DecisionProblem}) = nothing # Probably could be more efficient by storing the info in the internal function get_current_time(model::DecisionModel) @@ -261,35 +266,45 @@ function init_model_store_params!(model::DecisionModel) return end -function build_pre_step!(model::DecisionModel{<:DefaultDecisionProblem}) +function validate_time_series(model::DecisionModel{<:DefaultDecisionProblem}) + sys = get_system(model) + _, _, forecast_count = PSY.get_time_series_counts(sys) + if forecast_count < 1 + error( + "The system does not contain forecast data. A DecisionModel can't be built.", + ) + end + return +end + +function build_pre_step!(model::DecisionModel{<:DecisionProblem}) TimerOutputs.@timeit BUILD_PROBLEMS_TIMER "Build pre-step" begin + validate_template(model) + validate_time_series(model) if !isempty(model) @info "OptimizationProblem status not BuildStatus.EMPTY. Resetting" reset!(model) end # Initial time are set here because the information is specified in the # Simulation Sequence object and not at the problem creation. - @info "Initializing Optimization Container For a DecisionModel" init_optimization_container!( get_optimization_container(model), get_network_formulation(get_template(model)), get_system(model), ) - @info "Instantiating Network Model" - instantiate_network_model(model) @info "Initializing ModelStoreParams" init_model_store_params!(model) - - handle_initial_conditions!(model) set_status!(model, BuildStatus.IN_PROGRESS) end return end -function build_impl!(model::DecisionModel{<:DefaultDecisionProblem}) - validate_template(model) +function build_impl!(model::DecisionModel{<:DecisionProblem}) build_pre_step!(model) + @info "Instantiating Network Model" + instantiate_network_model(model) + handle_initial_conditions!(model) build_model!(model) serialize_metadata!(get_optimization_container(model), get_output_dir(model)) log_values(get_settings(model)) @@ -353,12 +368,12 @@ end Default implementation of build method for Operational Problems for models conforming with DecisionProblem specification. Overload this function to implement a custom build method """ -function build_model!(model::DecisionModel) +function build_model!(model::DecisionModel{<:DefaultDecisionProblem}) build_impl!(get_optimization_container(model), get_template(model), get_system(model)) return end -function reset!(model::DecisionModel) +function reset!(model::DecisionModel{<:DefaultDecisionProblem}) was_built_for_recurrent_solves = built_for_recurrent_solves(model) if was_built_for_recurrent_solves set_execution_count!(model, 0) diff --git a/src/operation/decision_model_store.jl b/src/operation/decision_model_store.jl index a6323dfd2d..102460b2ca 100644 --- a/src/operation/decision_model_store.jl +++ b/src/operation/decision_model_store.jl @@ -31,6 +31,9 @@ function initialize_storage!( params::ModelStoreParams, ) num_of_executions = get_num_executions(params) + if length(get_time_steps(container)) < 1 + error("The time step count in the optimization container is not defined") + end time_steps_count = get_time_steps(container)[end] initial_time = get_initial_time(container) model_interval = get_interval(params) @@ -53,6 +56,7 @@ function initialize_storage!( results_container[key] = data end end + return end function write_result!( diff --git a/src/operation/emulation_model.jl b/src/operation/emulation_model.jl index f3e60c9d48..b71350744b 100644 --- a/src/operation/emulation_model.jl +++ b/src/operation/emulation_model.jl @@ -70,12 +70,6 @@ mutable struct EmulationModel{M <: EmulationProblem} <: OperationModel elseif name isa String name = Symbol(name) end - _, ts_count, _ = PSY.get_time_series_counts(sys) - if ts_count < 1 - error( - "The system does not contain Static TimeSeries data. An Emulation model can't be formulated.", - ) - end finalize_template!(template, sys) internal = ModelInternal( OptimizationContainer(sys, settings, jump_model, PSY.SingleTimeSeries), @@ -224,6 +218,7 @@ end get_problem_type(::EmulationModel{M}) where {M <: EmulationProblem} = M validate_template(::EmulationModel{<:EmulationProblem}) = nothing +validate_time_series(::EmulationModel{<:EmulationProblem}) = nothing function get_current_time(model::EmulationModel) execution_count = get_internal(model).execution_count @@ -250,8 +245,21 @@ function init_model_store_params!(model::EmulationModel) return end +function validate_time_series(model::EmulationModel{<:DefaultEmulationProblem}) + sys = get_system(model) + _, ts_count, _ = PSY.get_time_series_counts(sys) + if ts_count < 1 + error( + "The system does not contain Static TimeSeries data. An Emulation model can't be formulated.", + ) + end + return +end + function build_pre_step!(model::EmulationModel) TimerOutputs.@timeit BUILD_PROBLEMS_TIMER "Build pre-step" begin + validate_template(model) + validate_time_series(model) if !isempty(model) @info "EmulationProblem status not BuildStatus.EMPTY. Resetting" reset!(model) @@ -265,20 +273,19 @@ function build_pre_step!(model::EmulationModel) get_network_formulation(get_template(model)), get_system(model), ) - @info "Instantiating Network Model" - instantiate_network_model(model) @info "Initializing ModelStoreParams" init_model_store_params!(model) - handle_initial_conditions!(model) set_status!(model, BuildStatus.IN_PROGRESS) end return end -function build_impl!(model::EmulationModel{<:DefaultEmulationProblem}) - validate_template(model) +function build_impl!(model::EmulationModel{<:EmulationProblem}) build_pre_step!(model) + @info "Instantiating Network Model" + instantiate_network_model(model) + handle_initial_conditions!(model) build_model!(model) serialize_metadata!(get_optimization_container(model), get_output_dir(model)) log_values(get_settings(model)) diff --git a/src/operation/operation_model_interface.jl b/src/operation/operation_model_interface.jl index bb925f4441..53aae2f0fb 100644 --- a/src/operation/operation_model_interface.jl +++ b/src/operation/operation_model_interface.jl @@ -144,48 +144,53 @@ function write_initial_conditions_data!(model::OperationModel) end function handle_initial_conditions!(model::OperationModel) - settings = get_settings(model) - initialize_model = get_initialize_model(settings) - deserialize_initial_conditions = get_deserialize_initial_conditions(settings) - serialized_initial_conditions_file = get_initial_conditions_file(model) - custom_init_file = get_initialization_file(settings) - - if !initialize_model && deserialize_initial_conditions - throw( - IS.ConflictingInputsError( - "!initialize_model && deserialize_initial_conditions", - ), - ) - elseif !initialize_model && !isempty(custom_init_file) - throw(IS.ConflictingInputsError("!initialize_model && initialization_file")) - end - - if !initialize_model - @info "Skip build of initial conditions" - return - end + TimerOutputs.@timeit BUILD_PROBLEMS_TIMER "Model Initialization" begin + if isempty(get_template(model)) + return + end + settings = get_settings(model) + initialize_model = get_initialize_model(settings) + deserialize_initial_conditions = get_deserialize_initial_conditions(settings) + serialized_initial_conditions_file = get_initial_conditions_file(model) + custom_init_file = get_initialization_file(settings) + + if !initialize_model && deserialize_initial_conditions + throw( + IS.ConflictingInputsError( + "!initialize_model && deserialize_initial_conditions", + ), + ) + elseif !initialize_model && !isempty(custom_init_file) + throw(IS.ConflictingInputsError("!initialize_model && initialization_file")) + end - if !isempty(custom_init_file) - if !isfile(custom_init_file) - error("initialization_file = $custom_init_file does not exist") + if !initialize_model + @info "Skip build of initial conditions" + return end - if abspath(custom_init_file) != abspath(serialized_initial_conditions_file) - cp(custom_init_file, serialized_initial_conditions_file; force = true) + + if !isempty(custom_init_file) + if !isfile(custom_init_file) + error("initialization_file = $custom_init_file does not exist") + end + if abspath(custom_init_file) != abspath(serialized_initial_conditions_file) + cp(custom_init_file, serialized_initial_conditions_file; force = true) + end end - end - if deserialize_initial_conditions && isfile(serialized_initial_conditions_file) - set_initial_conditions_data!( - model.internal.container, - Serialization.deserialize(serialized_initial_conditions_file), - ) - @info "Deserialized initial_conditions_data" - else - @info "Make Initial Conditions Model" - build_initial_conditions!(model) - initialize!(model) + if deserialize_initial_conditions && isfile(serialized_initial_conditions_file) + set_initial_conditions_data!( + model.internal.container, + Serialization.deserialize(serialized_initial_conditions_file), + ) + @info "Deserialized initial_conditions_data" + else + @info "Make Initial Conditions Model" + build_initial_conditions!(model) + initialize!(model) + end + model.internal.ic_model_container = nothing end - model.internal.ic_model_container = nothing return end From 6c93513fbf8a2e9e2a8e94711bd9ea7aa4bca9b1 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 10:12:55 -0600 Subject: [PATCH 321/370] improvements to objective function --- src/core/optimization_container.jl | 34 ++++++++++++++++-------- src/operation/decision_model.jl | 2 +- src/operation/emulation_model.jl | 2 +- test/test_utils/mock_operation_models.jl | 2 +- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index 3cdff305be..30fcde7078 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -54,15 +54,30 @@ mutable struct ObjectiveFunction invariant_terms::JuMP.AbstractJuMPScalar variant_terms::GAE synchronized::Bool + sense::MOI.OptimizationSense + function ObjectiveFunction(invariant_terms::JuMP.AbstractJuMPScalar, + variant_terms::GAE, + synchronized::Bool, + sense::MOI.OptimizationSense = MOI.MIN_SENSE) + new(invariant_terms, variant_terms, synchronized, sense) + end end get_invariant_terms(v::ObjectiveFunction) = v.invariant_terms get_variant_terms(v::ObjectiveFunction) = v.variant_terms -get_objective_function(v::ObjectiveFunction) = v.variant_terms + v.invariant_terms +function get_objective_expression(v::ObjectiveFunction) + if iszero(v.variant_terms) + return v.invariant_terms + else + return JuMP.add_to_expression!(v.variant_terms, v.invariant_terms) + end +end +get_sense(v::ObjectiveFunction) = v.sense is_synchronized(v::ObjectiveFunction) = v.synchronized set_synchronized_status(v::ObjectiveFunction, value) = v.synchronized = value reset_variant_terms(v::ObjectiveFunction) = v.variant_terms = zero(JuMP.AffExpr) has_variant_terms(v::ObjectiveFunction) = !iszero(v.variant_terms) +set_sense!(v::ObjectiveFunction, sense::MOI.OptimizationSense) = v.sense = sense function ObjectiveFunction() return ObjectiveFunction( @@ -150,7 +165,7 @@ get_base_power(container::OptimizationContainer) = container.base_power get_constraints(container::OptimizationContainer) = container.constraints function cost_function_unsynch(container::OptimizationContainer) - obj_func = PSI.get_objective_function(container) + obj_func = PSI.get_objective_expression(container) if has_variant_terms(obj_func) && PSI.is_synchronized(container) PSI.set_synchronized_status(obj_func, false) PSI.reset_variant_terms(obj_func) @@ -183,9 +198,10 @@ get_variables(container::OptimizationContainer) = container.variables set_initial_conditions_data!(container::OptimizationContainer, data) = container.initial_conditions_data = data -get_objective_function(container::OptimizationContainer) = container.objective_function +get_objective_expression(container::OptimizationContainer) = container.objective_function is_synchronized(container::OptimizationContainer) = container.objective_function.synchronized +set_time_steps!(container::OptimizationContainer, time_steps::UnitRange{Int64}) = container.time_steps = time_steps function has_container_key( container::OptimizationContainer, @@ -588,11 +604,7 @@ function build_impl!( TimerOutputs.@timeit BUILD_PROBLEMS_TIMER "Objective" begin @debug "Building Objective" _group = LOG_GROUP_OPTIMIZATION_CONTAINER - JuMP.@objective( - container.JuMPmodel, - MOI.MIN_SENSE, - get_objective_function(container.objective_function) - ) + update_objective_function!(container) end @debug "Total operation count $(container.JuMPmodel.operator_counter)" _group = LOG_GROUP_OPTIMIZATION_CONTAINER @@ -604,9 +616,9 @@ end function update_objective_function!(container::OptimizationContainer) JuMP.@objective( - container.JuMPmodel, - MOI.MIN_SENSE, - get_objective_function(container.objective_function) + get_jump_model(container), + get_sense(container.objective_function), + get_objective_expression(container.objective_function) ) return end diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index 9dbfc499a1..20403486a2 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -528,7 +528,7 @@ function update_parameters!( end if !is_synchronized(model) update_objective_function!(get_optimization_container(model)) - obj_func = get_objective_function(get_optimization_container(model)) + obj_func = get_objective_expression(get_optimization_container(model)) set_synchronized_status(obj_func, true) end return diff --git a/src/operation/emulation_model.jl b/src/operation/emulation_model.jl index b71350744b..2186f8de4d 100644 --- a/src/operation/emulation_model.jl +++ b/src/operation/emulation_model.jl @@ -375,7 +375,7 @@ function update_parameters!(model::EmulationModel, data::DatasetContainer{InMemo end if !is_synchronized(model) update_objective_function!(get_optimization_container(model)) - obj_func = get_objective_function(get_optimization_container(model)) + obj_func = get_objective_expression(get_optimization_container(model)) set_synchronized_status(obj_func, true) end return diff --git a/test/test_utils/mock_operation_models.jl b/test/test_utils/mock_operation_models.jl index 49b276d237..f1166c01cb 100644 --- a/test/test_utils/mock_operation_models.jl +++ b/test/test_utils/mock_operation_models.jl @@ -139,7 +139,7 @@ function mock_construct_device!( JuMP.@objective( PSI.get_jump_model(problem), MOI.MIN_SENSE, - PSI.get_objective_function( + PSI.get_objective_expression( PSI.get_optimization_container(problem).objective_function, ) ) From d8f1edbe5db8cb46dba114e85fdd3ac8679d6a52 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 12:26:30 -0600 Subject: [PATCH 322/370] improve docs pages --- .../adding_new_problem_model.md | 6 -- .../structure_of_operation_problem.md | 10 +++ docs/src/modeler_guide/definitions.md | 6 +- .../adding_new_device_formulation.md | 0 .../src/tutorials/adding_new_problem_model.md | 85 +++++++++++++++++++ .../tutorials/basics_of_developing_models.md | 3 + 6 files changed, 101 insertions(+), 9 deletions(-) delete mode 100644 docs/src/model_developer_guide/adding_new_problem_model.md create mode 100644 docs/src/model_developer_guide/structure_of_operation_problem.md rename docs/src/{model_developer_guide => tutorials}/adding_new_device_formulation.md (100%) create mode 100644 docs/src/tutorials/adding_new_problem_model.md create mode 100644 docs/src/tutorials/basics_of_developing_models.md diff --git a/docs/src/model_developer_guide/adding_new_problem_model.md b/docs/src/model_developer_guide/adding_new_problem_model.md deleted file mode 100644 index 9083c2309c..0000000000 --- a/docs/src/model_developer_guide/adding_new_problem_model.md +++ /dev/null @@ -1,6 +0,0 @@ -# Adding an Operations Problem Model - -## Decision Problem - - -## Emulation Problem diff --git a/docs/src/model_developer_guide/structure_of_operation_problem.md b/docs/src/model_developer_guide/structure_of_operation_problem.md new file mode 100644 index 0000000000..b4d67b51d0 --- /dev/null +++ b/docs/src/model_developer_guide/structure_of_operation_problem.md @@ -0,0 +1,10 @@ +# Structure of an operations problem model + +In most cases operation problem models are optimization models. Although in `PowerSimulations.jl` it is +possible to define arbitrary problems that can reflect heuristic decision rules, this is not the common case. This page focuses on explaining the structure of operations problems that employ and optimization problem and solver. + +The first aspect to consider when thinking about developing a model compatible with `PowerSimulations.jl` is that although we support all of `JuMP.jl` objects, you need to employ [anonymous constraints and variables in JuMP](https://jump.dev/JuMP.jl/stable/manual/variables/#anonymous_variables) +and register the constraints, variables and other optimization objects into PowerSimulations.jl's optimization container. Otherwise the features to use your problem in the simulation like the coordination with other problems and post processing won't work. + +!!! info + The requirements for the simulation of Power Systems operations are more strict than solving an optimization problem once with just `JuMP.jl`. The requirements imposed by `PowerSimulations.jl` to integrate your models in a simulation are designed to help with other complex operations that go beyond `JuMP.jl` scope. diff --git a/docs/src/modeler_guide/definitions.md b/docs/src/modeler_guide/definitions.md index cc42de6e72..77a91065e0 100644 --- a/docs/src/modeler_guide/definitions.md +++ b/docs/src/modeler_guide/definitions.md @@ -10,12 +10,12 @@ ## H -* *Horizon*: The number of steps in the look-ahead of a decision problem. For instance, a Day-ahead problem usually has a 48 step horizon. +* *Horizon*: The number of steps in the look-ahead of a decision problem. For instance, a Day-Ahead problem usually has a 48 step horizon. Check the time [Time Series Data Section in PowerSystems.jl](https://nrel-sienna.github.io/PowerSystems.jl/stable/modeler_guide/time_series/) ## I -* *Interval*: +* *Interval*: The amount of time between updates to the decision problem. For instance, Day-Ahead problems usually have a 24-hour intervals and Real-Time problems have 5-minute intervals. Check the time [Time Series Data Section in PowerSystems.jl](https://nrel-sienna.github.io/PowerSystems.jl/stable/modeler_guide/time_series/) ## R -* *Resolution*: The amount of time between timesteps in a simulation. For instance 1-hour or 5-minutes. In Julia these are defined using the syntax `Hour(1)` and `Minute(5)` +* *Resolution*: The amount of time between timesteps in a simulation. For instance 1-hour or 5-minutes. In Julia these are defined using the syntax `Hour(1)` and `Minute(5)`. Check the time [Time Series Data Section in PowerSystems.jl](https://nrel-sienna.github.io/PowerSystems.jl/stable/modeler_guide/time_series/) diff --git a/docs/src/model_developer_guide/adding_new_device_formulation.md b/docs/src/tutorials/adding_new_device_formulation.md similarity index 100% rename from docs/src/model_developer_guide/adding_new_device_formulation.md rename to docs/src/tutorials/adding_new_device_formulation.md diff --git a/docs/src/tutorials/adding_new_problem_model.md b/docs/src/tutorials/adding_new_problem_model.md new file mode 100644 index 0000000000..0134dd58b4 --- /dev/null +++ b/docs/src/tutorials/adding_new_problem_model.md @@ -0,0 +1,85 @@ +# Adding an Operations Problem Model + +This tutorial will show how to create a custom decision problem model. These cases are the ones +where the user want to solve a fully specified problem. Some examples of custom decision models include: + +- Solving a custom Security Constrained Unit Commitment Problem +- Solving a market agent utility maximization Problem. See examples of this functionality in HybridSystemsSimulations.jl + +The tutorial follows the usual steps for operational model building. First, build the decision model in isolation and second integrate int a simulation. In most cases there will be more than one way of achieving +the same objective when it comes to implementing the model. This guide shows a general set of steps and requirements but it is by no means an exhaustive and detailed guide on developing custom decision models. + +!!! warning + All the code in this tutorial is considered "pseudo-code". If you copy-paste will likely not work out of the box. You need to develop the internals of the functions correctly for the examples below to work. + +## General Rules + +1. As a general rule you need to understand Julia's terminology such as multiple dispatch, parametried structs and method overloading among others. Developing custom models for an operational simulation is highly technical task and requires skilled development. This tuturial also requires good understanding of PowerSystems.jl data structures and features which are covered in the tutorials section of PowerSystems.jl documentation. +Finally, developing a custom model decision model that will employ an optimization model under the hood requires understanding JuMP.jl. + +2. Need to employ [anonymous constraints and variables in JuMP](https://jump.dev/JuMP.jl/stable/manual/variables/#anonymous_variables) +and register the constraints, variables and other optimization objects into PowerSimulations.jl's optimization container. Otherwise the +features to use your problem in the simulation like the coordination with other problems and post processing won't work. More on this in the section [How to develop your `build_model!` function](@ref) below. + +3. Overload the required methods for your custom decision models. In some cases it will be possible to re-use some of the other methods that exist in PowerSimulations to make life easier for variable addition and constraint creation but this is not required. + +## Decision Problem + +### Step 1: Define a Custom Decision Problem + +Define a decision problem struct as a subtype of `PowerSimulations.DecisionProblem`. This requirement will enable a lot of the underlying functionality that relies on multiple dispatch. DecisionProblems are used to parameterize the behavior of `DecisionModel` objects which are just containers +for the parameters, references and the optimization problem. + +It is possible to define a Custom Decision Problem that gives the user full control over the build, solve and execution process since it imposes less requirements on the developer. However, with less requirements there are also less check and validations performed inside of PowerSimulations which might lead to unexpected erros. + +```julia +struct MyCustomDecisionProblem <: PSI.DecisionProblem end +``` + +Alternatevely, it is possible to define a Custom Decision Problem subtyping from `DefaultDecisionProblem` which imposes more requirements and structure onto the developer but employs more checks and validations in the process. Be aware that this route will decrease the flexibility of what can be done inside the custom model. + +```julia +struct MyCustomDecisionProblem <: PSI.DefaultDecisionProblem end +``` + +Once the problem type is defined, initialize the decision model container with your custom decision problem passing the solver and some of the settings you need for the solution of the problem. For custom problems some of the settings need manual implementation by the developer. Settings availability is also dependent on wether you choose to subtype from `PSI.DecisionProblem` or `PSI.DefaultDecisionProblem` + +```julia +my_model = DecisionModel{MyCustomDecisionProblem}( + sys; + name = "MyModel", + optimizer = optimizer_with_attributes(HiGHS.Optimizer), + optimizer_solve_log_print = true, +) +``` + +#### Mandatory Method Overloads + +1. `build_model!`: This method build the `JuMP` optimization model. + +#### Optional Method Overloads + +These methods can be defined optionally for your problem. By default for problems subtyped from `DecisionProblem` these checks are not executed. If the problems are subtyped from `DefaultDecisionProblem` these checks are always conducted with PowerSimulations defaults and require compliance with those defaults to pass. In any case, these can be overloaded when necessary depending on the problem requirements. + +1. `validate_template` +2. `validate_time_series` +3. `reset!` +4. `solve_impl!` + +### How to develop your `build_model!` function + + + +```julia +function PSI.build_model!(model::PSI.DecisionModel{MyCustomDecisionProblem}) + container = PSI.get_optimization_container(model) + PSI.set_time_steps!(container, 1:24) # <- Mandatory + system = PSI.get_system(model) + + + + update_objective_function!(container) # <- Mandatory +end +``` + +## Emulation Problem diff --git a/docs/src/tutorials/basics_of_developing_models.md b/docs/src/tutorials/basics_of_developing_models.md new file mode 100644 index 0000000000..a027918d6a --- /dev/null +++ b/docs/src/tutorials/basics_of_developing_models.md @@ -0,0 +1,3 @@ +# Basics of Developing Operation Models + +Check the page [PowerSimulations Structure](@ref) for more background on PowerSimulations.jl From d0e4cedf2d92b72278e19af91062168d5ae25166 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 14:23:23 -0600 Subject: [PATCH 323/370] formatter --- src/core/optimization_container.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index 30fcde7078..eb0cb5b93c 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -201,7 +201,8 @@ set_initial_conditions_data!(container::OptimizationContainer, data) = get_objective_expression(container::OptimizationContainer) = container.objective_function is_synchronized(container::OptimizationContainer) = container.objective_function.synchronized -set_time_steps!(container::OptimizationContainer, time_steps::UnitRange{Int64}) = container.time_steps = time_steps +set_time_steps!(container::OptimizationContainer, time_steps::UnitRange{Int64}) = + container.time_steps = time_steps function has_container_key( container::OptimizationContainer, From ff35590fc86a3cabe6eda553386b1910089270be Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 15:51:34 -0600 Subject: [PATCH 324/370] remove more hybrid --- docs/src/api/PowerSimulations.md | 20 -------------------- src/PowerSimulations.jl | 7 ------- src/core/constraints.jl | 6 ------ src/core/variables.jl | 8 -------- 4 files changed, 41 deletions(-) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index 6440195532..923befca92 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -130,14 +130,6 @@ PowerAboveMinimumVariable ReservationVariable ``` -### Common for Hydro and Storage Variables - -```@docs -ActivePowerOutVariable -ActivePowerInVariable -EnergyVariable -``` - ### Branches and Network Variables ```@docs @@ -236,18 +228,6 @@ EqualityConstraint ``` -### Hydro and Storage Constraints - -```@docs -EnergyBalanceConstraint -EnergyBudgetConstraint -EnergyCapacityConstraint -EnergyCapacityDownConstraint -EnergyCapacityUpConstraint -EnergyTargetConstraint -RangeLimitConstraint -``` - ### Branches Constraints ```@docs diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 5b6b431b30..bce2464d75 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -212,7 +212,6 @@ export ReactivePowerVariable export ReservationVariable export ActivePowerReserveVariable export ServiceRequirementVariable -export WaterSpillageVariable export StartVariable export StopVariable export SteadyStateFrequencyDeviation @@ -256,12 +255,6 @@ export CommitmentConstraint export CopperPlateBalanceConstraint export DurationConstraint export EnergyBalanceConstraint -export EnergyBudgetConstraint -export EnergyCapacityConstraint -export EnergyCapacityDownConstraint -export EnergyCapacityUpConstraint -export EnergyLimitConstraint -export EnergyTargetConstraint export EqualityConstraint export FeedforwardSemiContinousConstraint export FeedforwardUpperBoundConstraint diff --git a/src/core/constraints.jl b/src/core/constraints.jl index d0a037c6e4..47a2043ef9 100644 --- a/src/core/constraints.jl +++ b/src/core/constraints.jl @@ -36,12 +36,6 @@ struct CommitmentConstraint <: ConstraintType end struct CopperPlateBalanceConstraint <: ConstraintType end struct DurationConstraint <: ConstraintType end struct EnergyBalanceConstraint <: ConstraintType end -struct EnergyBudgetConstraint <: ConstraintType end -struct EnergyCapacityConstraint <: ConstraintType end -struct EnergyCapacityDownConstraint <: ConstraintType end -struct EnergyCapacityUpConstraint <: ConstraintType end -struct EnergyLimitConstraint <: ConstraintType end # not being used -struct EnergyTargetConstraint <: ConstraintType end struct EqualityConstraint <: ConstraintType end struct FeedforwardSemiContinousConstraint <: ConstraintType end struct FeedforwardIntegralLimitConstraint <: ConstraintType end diff --git a/src/core/variables.jl b/src/core/variables.jl index 8d04b12216..083fa93f84 100644 --- a/src/core/variables.jl +++ b/src/core/variables.jl @@ -104,13 +104,6 @@ struct ActivePowerReserveVariable <: VariableType end struct ServiceRequirementVariable <: VariableType end -""" -Struct to dispatch the creation of energy (water) spillage variable representing energy released from a storage/reservoir not injected into the network - -Docs abbreviation: ``S`` -""" -struct WaterSpillageVariable <: VariableType end - struct StartVariable <: VariableType end struct StopVariable <: VariableType end @@ -208,7 +201,6 @@ convert_result_to_natural_units(::Type{EnergyVariable}) = true convert_result_to_natural_units(::Type{ReactivePowerVariable}) = true convert_result_to_natural_units(::Type{ActivePowerReserveVariable}) = true convert_result_to_natural_units(::Type{ServiceRequirementVariable}) = true -# convert_result_to_natural_units(::Type{WaterSpillageVariable }) = true # TODO: is this pu? convert_result_to_natural_units(::Type{AreaMismatchVariable}) = true convert_result_to_natural_units(::Type{DeltaActivePowerUpVariable}) = true convert_result_to_natural_units(::Type{DeltaActivePowerDownVariable}) = true From fbedd511fce4ac69b8fa95b0eaafbcc845597c37 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 16:39:07 -0600 Subject: [PATCH 325/370] more hydro removal --- docs/src/api/PowerSimulations.md | 8 ++------ src/PowerSimulations.jl | 2 -- src/core/parameters.jl | 31 ------------------------------- test/test_simulation_results.jl | 2 -- 4 files changed, 2 insertions(+), 41 deletions(-) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index 923befca92..2f8d8e47b4 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -259,19 +259,15 @@ FeedforwardEnergyTargetConstraint # Parameters -### Time Series Parameters +## Time Series Parameters ```@docs ActivePowerTimeSeriesParameter ReactivePowerTimeSeriesParameter RequirementTimeSeriesParameter -EnergyTargetTimeSeriesParameter -EnergyBudgetTimeSeriesParameter -InflowTimeSeriesParameter -OutflowTimeSeriesParameter ``` -### Variable Value Parameters +## Variable Value Parameters ```@docs UpperBoundValueParameter diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index bce2464d75..3240de1f95 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -308,8 +308,6 @@ export StartupTimeLimitTemperatureConstraint export ActivePowerTimeSeriesParameter export ReactivePowerTimeSeriesParameter export RequirementTimeSeriesParameter -export EnergyTargetTimeSeriesParameter -export EnergyBudgetTimeSeriesParameter # Feedforward Parameters export OnStatusParameter diff --git a/src/core/parameters.jl b/src/core/parameters.jl index d20f0b40e4..a923e707c5 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -281,26 +281,6 @@ Paramter to define requirement time series """ struct RequirementTimeSeriesParameter <: TimeSeriesParameter end -""" -Parameter to define energy storage target level time series -""" -struct EnergyTargetTimeSeriesParameter <: TimeSeriesParameter end - -""" -Parameter to define energy budget time series -""" -struct EnergyBudgetTimeSeriesParameter <: TimeSeriesParameter end - -""" -Parameter to define energy inflow to storage or reservoir time series -""" -struct InflowTimeSeriesParameter <: TimeSeriesParameter end - -""" -Parameter to define energy outflow from storage or reservoir time series -""" -struct OutflowTimeSeriesParameter <: TimeSeriesParameter end - abstract type VariableValueParameter <: RightHandSideParameter end """ @@ -328,11 +308,6 @@ Parameter to define fixed output values """ struct FixValueParameter <: VariableValueParameter end -""" -Parameter to define energy storage target -""" -struct EnergyTargetParameter <: VariableValueParameter end - """ Parameter to define cost function coefficient """ @@ -348,11 +323,5 @@ convert_result_to_natural_units(::Type{<:ParameterType}) = false convert_result_to_natural_units(::Type{ActivePowerTimeSeriesParameter}) = true convert_result_to_natural_units(::Type{ReactivePowerTimeSeriesParameter}) = true convert_result_to_natural_units(::Type{RequirementTimeSeriesParameter}) = true -convert_result_to_natural_units(::Type{EnergyTargetTimeSeriesParameter}) = true -convert_result_to_natural_units(::Type{EnergyBudgetTimeSeriesParameter}) = true -#convert_result_to_natural_units(::Type{InflowTimeSeriesParameter}) = true # TODO: is this pu? -#convert_result_to_natural_units(::Type{OutflowTimeSeriesParameter}) = true # TODO: is this pu? convert_result_to_natural_units(::Type{UpperBoundValueParameter}) = true convert_result_to_natural_units(::Type{LowerBoundValueParameter}) = true -convert_result_to_natural_units(::Type{EnergyLimitParameter}) = true -convert_result_to_natural_units(::Type{EnergyTargetParameter}) = true diff --git a/test/test_simulation_results.jl b/test/test_simulation_results.jl index 9080afd737..cac3e635cb 100644 --- a/test/test_simulation_results.jl +++ b/test/test_simulation_results.jl @@ -81,10 +81,8 @@ NATURAL_UNITS_VALUES = [ "ActivePowerTimeSeriesParameter__HydroEnergyReservoir", "ActivePowerTimeSeriesParameter__RenewableDispatch", "ActivePowerTimeSeriesParameter__InterruptiblePowerLoad", - "EnergyLimitParameter__HydroEnergyReservoir", "SystemBalanceSlackDown__System", "SystemBalanceSlackUp__System", - "EnergyBudgetTimeSeriesParameter__HydroEnergyReservoir", ] function compare_results(rpath, epath, model, field, name, timestamp) From 4d6ae2a788f0e81042890d8561c3358c950d7c32 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 17:04:30 -0600 Subject: [PATCH 326/370] comment out repeated code with HydroPowerSims --- .../device_constructors/hydrogeneration_constructor.jl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index 75673eba77..5d04b0be29 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -70,6 +70,7 @@ function construct_device!( return end +#= """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation """ @@ -132,6 +133,7 @@ function construct_device!( return end + function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -178,6 +180,7 @@ function construct_device!( return end +=# """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation @@ -191,7 +194,7 @@ function construct_device!( network_model::NetworkModel{S}, ) where { H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, + D <: HydroDispatchRunOfRiver, S <: PM.AbstractActivePowerModel, } devices = @@ -232,6 +235,7 @@ function construct_device!( return end +#= function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -270,6 +274,7 @@ function construct_device!( add_constraint_dual!(container, sys, model) return end +=# """ Construct model for HydroGen with RunOfRiver Commitment Formulation From 09a6376eb4865dc5f3598150773c072c186c86e0 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 17:11:09 -0600 Subject: [PATCH 327/370] formatter --- .../device_constructors/hydrogeneration_constructor.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index 5d04b0be29..4e504bb613 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -133,7 +133,6 @@ function construct_device!( return end - function construct_device!( container::OptimizationContainer, sys::PSY.System, From a5eedb2d20f187bd8c39277e0a3393644f9ff358 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 13 Jul 2023 10:47:27 -0600 Subject: [PATCH 328/370] fix hydro tests and references --- docs/src/tutorials/decision_problem.md | 2 +- .../hydrogeneration_constructor.jl | 12 +++++------- src/devices_models/devices/hydro_generation.jl | 9 +-------- src/simulation/simulation_results.jl | 1 - 4 files changed, 7 insertions(+), 17 deletions(-) diff --git a/docs/src/tutorials/decision_problem.md b/docs/src/tutorials/decision_problem.md index 52cc8c4886..584a986811 100644 --- a/docs/src/tutorials/decision_problem.md +++ b/docs/src/tutorials/decision_problem.md @@ -64,7 +64,7 @@ set_device_model!(template_uc, ThermalStandard, ThermalStandardUnitCommitment) set_device_model!(template_uc, RenewableDispatch, RenewableFullDispatch) set_device_model!(template_uc, PowerLoad, StaticPowerLoad) set_device_model!(template_uc, HydroDispatch, FixedOutput) -set_device_model!(template_uc, HydroEnergyReservoir, HydroDispatchRunOfRiver) +set_device_model!(template_uc, HydroDispatchRunOfRiver, HydroDispatchRunOfRiver) set_device_model!(template_uc, RenewableFix, FixedOutput) ``` diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index 4e504bb613..dd43264c65 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -70,7 +70,6 @@ function construct_device!( return end -#= """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation """ @@ -82,7 +81,7 @@ function construct_device!( network_model::NetworkModel{S}, ) where { H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, + D <: Union{HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}, S <: PM.AbstractPowerModel, } devices = @@ -141,7 +140,7 @@ function construct_device!( network_model::NetworkModel{S}, ) where { H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, + D <: Union{HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}, S <: PM.AbstractPowerModel, } devices = @@ -179,7 +178,6 @@ function construct_device!( return end -=# """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation @@ -234,7 +232,7 @@ function construct_device!( return end -#= + function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -243,7 +241,7 @@ function construct_device!( network_model::NetworkModel{S}, ) where { H <: PSY.HydroGen, - D <: AbstractHydroDispatchFormulation, + D <: HydroDispatchRunOfRiver, S <: PM.AbstractActivePowerModel, } devices = @@ -273,7 +271,7 @@ function construct_device!( add_constraint_dual!(container, sys, model) return end -=# + """ Construct model for HydroGen with RunOfRiver Commitment Formulation diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 95cd47efec..34a8ae1de8 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -62,13 +62,6 @@ variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGe #! format: on -function get_initial_conditions_device_model( - ::OperationModel, - model::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroEnergyReservoir} - return model -end - function get_initial_conditions_device_model( ::OperationModel, ::DeviceModel{T, <:AbstractHydroFormulation}, @@ -89,7 +82,7 @@ end function get_default_attributes( ::Type{T}, ::Type{D}, -) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} +) where {T <: PSY.HydroGen, D <:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}} return Dict{String, Any}("reservation" => false) end diff --git a/src/simulation/simulation_results.jl b/src/simulation/simulation_results.jl index 7cbfa5b53c..142f17b5ee 100644 --- a/src/simulation/simulation_results.jl +++ b/src/simulation/simulation_results.jl @@ -230,7 +230,6 @@ An example JSON file demonstrating possible options is below. Note that `start_t "name": "ED", "variables": [ "P__ThermalStandard", - "E__HydroEnergyReservoir" ], "parameters": [ "all" From ec1a8f8e6a9d68cf44f47d12cdcec01e813656f7 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 13 Jul 2023 10:50:41 -0600 Subject: [PATCH 329/370] formatter --- .../device_constructors/hydrogeneration_constructor.jl | 2 -- src/devices_models/devices/hydro_generation.jl | 5 ++++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index dd43264c65..534038d7f6 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -232,7 +232,6 @@ function construct_device!( return end - function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -272,7 +271,6 @@ function construct_device!( return end - """ Construct model for HydroGen with RunOfRiver Commitment Formulation """ diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 34a8ae1de8..2767ff8095 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -82,7 +82,10 @@ end function get_default_attributes( ::Type{T}, ::Type{D}, -) where {T <: PSY.HydroGen, D <:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}} +) where { + T <: PSY.HydroGen, + D <: Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}, +} return Dict{String, Any}("reservation" => false) end From 3f4e38ac0aea013e1301d8b3244a677966b3c00b Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 13 Jul 2023 10:57:12 -0600 Subject: [PATCH 330/370] change abstract type call --- src/devices_models/devices/hydro_generation.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 2767ff8095..9773698f0e 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -65,8 +65,8 @@ variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGe function get_initial_conditions_device_model( ::OperationModel, ::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroDispatch} - return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) +) where {T <: PSY.HydroGen} + return DeviceModel(T, HydroDispatchRunOfRiver) end function get_default_time_series_names( From 557d5b85c825fd21f8ddfa1aca37d2e62357f0cc Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Fri, 14 Jul 2023 16:57:01 -0600 Subject: [PATCH 331/370] fix initial condition model --- src/devices_models/devices/hydro_generation.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl index 9773698f0e..f0399d91f1 100644 --- a/src/devices_models/devices/hydro_generation.jl +++ b/src/devices_models/devices/hydro_generation.jl @@ -66,7 +66,7 @@ function get_initial_conditions_device_model( ::OperationModel, ::DeviceModel{T, <:AbstractHydroFormulation}, ) where {T <: PSY.HydroGen} - return DeviceModel(T, HydroDispatchRunOfRiver) + return DeviceModel(T, HydroCommitmentRunOfRiver) end function get_default_time_series_names( From 5d4e3fc112d8858120dd0860ddefbf7e739ffa0f Mon Sep 17 00:00:00 2001 From: rodrigomha Date: Mon, 17 Jul 2023 16:25:00 -0700 Subject: [PATCH 332/370] return energytargetparameter --- src/core/parameters.jl | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/core/parameters.jl b/src/core/parameters.jl index a923e707c5..ea6baa0fa9 100644 --- a/src/core/parameters.jl +++ b/src/core/parameters.jl @@ -302,10 +302,9 @@ struct OnStatusParameter <: VariableValueParameter end Parameter to define energy limit """ struct EnergyLimitParameter <: VariableValueParameter end - -""" -Parameter to define fixed output values -""" +# TODO: Check if EnergyTargetParameter and EnergyLimitParameter should be removed +# This affects feedforwards that can break if not defined +struct EnergyTargetParameter <: VariableValueParameter end struct FixValueParameter <: VariableValueParameter end """ @@ -325,3 +324,6 @@ convert_result_to_natural_units(::Type{ReactivePowerTimeSeriesParameter}) = true convert_result_to_natural_units(::Type{RequirementTimeSeriesParameter}) = true convert_result_to_natural_units(::Type{UpperBoundValueParameter}) = true convert_result_to_natural_units(::Type{LowerBoundValueParameter}) = true +# TODO: Check if EnergyLimitParameter and EnergyTargetParameter should be removed +convert_result_to_natural_units(::Type{EnergyLimitParameter}) = true +convert_result_to_natural_units(::Type{EnergyTargetParameter}) = true From 95a1b333d5d2600b2314ab47cb279931be6822bf Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 17:04:30 -0600 Subject: [PATCH 333/370] comment out repeated code with HydroPowerSims --- .../device_constructors/hydrogeneration_constructor.jl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index 534038d7f6..dcd8b3296b 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -70,6 +70,7 @@ function construct_device!( return end +#= """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation """ @@ -132,6 +133,7 @@ function construct_device!( return end + function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -178,6 +180,7 @@ function construct_device!( return end +=# """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation @@ -232,6 +235,7 @@ function construct_device!( return end +#= function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -270,6 +274,7 @@ function construct_device!( add_constraint_dual!(container, sys, model) return end +=# """ Construct model for HydroGen with RunOfRiver Commitment Formulation From 43fa9bf3fea9700abd354bd429dfcf2f3c8e9128 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 17:11:09 -0600 Subject: [PATCH 334/370] formatter --- .../device_constructors/hydrogeneration_constructor.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index dcd8b3296b..ff2d5c4f59 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -133,7 +133,6 @@ function construct_device!( return end - function construct_device!( container::OptimizationContainer, sys::PSY.System, From df9de349b834240f29f1bd7d7c633d8ebfa6b015 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 13 Jul 2023 10:47:27 -0600 Subject: [PATCH 335/370] fix hydro tests and references --- .../device_constructors/hydrogeneration_constructor.jl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index ff2d5c4f59..dd43264c65 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -70,7 +70,6 @@ function construct_device!( return end -#= """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation """ @@ -179,7 +178,6 @@ function construct_device!( return end -=# """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation @@ -234,7 +232,7 @@ function construct_device!( return end -#= + function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -273,7 +271,7 @@ function construct_device!( add_constraint_dual!(container, sys, model) return end -=# + """ Construct model for HydroGen with RunOfRiver Commitment Formulation From 6e384869f2c8cf359c4b97aae4e3b45149a1a51f Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 13 Jul 2023 10:50:41 -0600 Subject: [PATCH 336/370] formatter --- .../device_constructors/hydrogeneration_constructor.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index dd43264c65..534038d7f6 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -232,7 +232,6 @@ function construct_device!( return end - function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -272,7 +271,6 @@ function construct_device!( return end - """ Construct model for HydroGen with RunOfRiver Commitment Formulation """ From 4df6a32ec0b18dd4df73922f41b485d9be047e93 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 9 Aug 2023 11:35:10 -0600 Subject: [PATCH 337/370] address PR comments --- .../structure_of_operation_problem.md | 2 +- docs/src/modeler_guide/running_a_simulation.md | 4 +++- docs/src/tutorials/adding_new_problem_model.md | 12 ++++++------ src/operation/decision_model.jl | 4 ++-- src/operation/emulation_model.jl | 4 ++-- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/docs/src/model_developer_guide/structure_of_operation_problem.md b/docs/src/model_developer_guide/structure_of_operation_problem.md index b4d67b51d0..202bbe0cb0 100644 --- a/docs/src/model_developer_guide/structure_of_operation_problem.md +++ b/docs/src/model_developer_guide/structure_of_operation_problem.md @@ -1,7 +1,7 @@ # Structure of an operations problem model In most cases operation problem models are optimization models. Although in `PowerSimulations.jl` it is -possible to define arbitrary problems that can reflect heuristic decision rules, this is not the common case. This page focuses on explaining the structure of operations problems that employ and optimization problem and solver. +possible to define arbitrary problems that can reflect heuristic decision rules, this is not the common case. This page focuses on explaining the structure of operations problems that employ an optimization problem and solver. The first aspect to consider when thinking about developing a model compatible with `PowerSimulations.jl` is that although we support all of `JuMP.jl` objects, you need to employ [anonymous constraints and variables in JuMP](https://jump.dev/JuMP.jl/stable/manual/variables/#anonymous_variables) and register the constraints, variables and other optimization objects into PowerSimulations.jl's optimization container. Otherwise the features to use your problem in the simulation like the coordination with other problems and post processing won't work. diff --git a/docs/src/modeler_guide/running_a_simulation.md b/docs/src/modeler_guide/running_a_simulation.md index c0fe63b512..906bff25a2 100644 --- a/docs/src/modeler_guide/running_a_simulation.md +++ b/docs/src/modeler_guide/running_a_simulation.md @@ -11,4 +11,6 @@ TODO ## Sequencing -TODO +In a typical simulation pipeline, we want to connect daily (24-hours) day-ahead unit commitment problems, with multiple economic dispatch problems. Usually, our day-ahead unit commitment problem will have an hourly (1-hour) resolution, while the economic dispatch will have a 5-minute resolution. + +Depending on your problem, it is common to use a 2-day look-ahead for unit commitment problems, so in this case, the Day-Ahead problem will have: resolution = Hour(1) with interval = Hour(24) and horizon = 48. In the case of the economic dispatch problem, it is common to use a look-ahead of two hours. Thus, the Real-Time problem will have: resolution = Minute(5), with interval = Minute(5) (we only store the first operating point) and horizon = 24 (24 time steps of 5 minutes are 120 minutes, that is 2 hours). diff --git a/docs/src/tutorials/adding_new_problem_model.md b/docs/src/tutorials/adding_new_problem_model.md index 0134dd58b4..795a3f1111 100644 --- a/docs/src/tutorials/adding_new_problem_model.md +++ b/docs/src/tutorials/adding_new_problem_model.md @@ -6,22 +6,22 @@ where the user want to solve a fully specified problem. Some examples of custom - Solving a custom Security Constrained Unit Commitment Problem - Solving a market agent utility maximization Problem. See examples of this functionality in HybridSystemsSimulations.jl -The tutorial follows the usual steps for operational model building. First, build the decision model in isolation and second integrate int a simulation. In most cases there will be more than one way of achieving +The tutorial follows the usual steps for operational model building. First, build the decision model in isolation and second, integrate it into a simulation. In most cases there will be more than one way of achieving the same objective when it comes to implementing the model. This guide shows a general set of steps and requirements but it is by no means an exhaustive and detailed guide on developing custom decision models. !!! warning - All the code in this tutorial is considered "pseudo-code". If you copy-paste will likely not work out of the box. You need to develop the internals of the functions correctly for the examples below to work. + All the code in this tutorial is considered "pseudo-code". Copy-paste will likely not work out of the box. You need to develop the internals of the functions correctly for the examples below to work. ## General Rules -1. As a general rule you need to understand Julia's terminology such as multiple dispatch, parametried structs and method overloading among others. Developing custom models for an operational simulation is highly technical task and requires skilled development. This tuturial also requires good understanding of PowerSystems.jl data structures and features which are covered in the tutorials section of PowerSystems.jl documentation. +1. As a general rule you need to understand Julia's terminology such as multiple dispatch, parametric structs and method overloading, among others. Developing custom models for an operational simulation is a highly technical task and requires skilled development. This tutorial also requires good understanding of PowerSystems.jl data structures and features which are covered in the tutorials section of PowerSystems.jl documentation. Finally, developing a custom model decision model that will employ an optimization model under the hood requires understanding JuMP.jl. 2. Need to employ [anonymous constraints and variables in JuMP](https://jump.dev/JuMP.jl/stable/manual/variables/#anonymous_variables) and register the constraints, variables and other optimization objects into PowerSimulations.jl's optimization container. Otherwise the features to use your problem in the simulation like the coordination with other problems and post processing won't work. More on this in the section [How to develop your `build_model!` function](@ref) below. -3. Overload the required methods for your custom decision models. In some cases it will be possible to re-use some of the other methods that exist in PowerSimulations to make life easier for variable addition and constraint creation but this is not required. +3. Implement the required methods for your custom decision models. In some cases it will be possible to re-use some of the other methods that exist in PowerSimulations to make life easier for variable addition and constraint creation but this is not required. ## Decision Problem @@ -30,7 +30,7 @@ features to use your problem in the simulation like the coordination with other Define a decision problem struct as a subtype of `PowerSimulations.DecisionProblem`. This requirement will enable a lot of the underlying functionality that relies on multiple dispatch. DecisionProblems are used to parameterize the behavior of `DecisionModel` objects which are just containers for the parameters, references and the optimization problem. -It is possible to define a Custom Decision Problem that gives the user full control over the build, solve and execution process since it imposes less requirements on the developer. However, with less requirements there are also less check and validations performed inside of PowerSimulations which might lead to unexpected erros. +It is possible to define a Custom Decision Problem that gives the user full control over the build, solve and execution process since it imposes less requirements on the developer. However, with less requirements there are also less checks and validations performed inside of PowerSimulations which might lead to unexpected errors ```julia struct MyCustomDecisionProblem <: PSI.DecisionProblem end @@ -53,7 +53,7 @@ my_model = DecisionModel{MyCustomDecisionProblem}( ) ``` -#### Mandatory Method Overloads +#### Mandatory Method Implementations 1. `build_model!`: This method build the `JuMP` optimization model. diff --git a/src/operation/decision_model.jl b/src/operation/decision_model.jl index 20403486a2..8287346b53 100644 --- a/src/operation/decision_model.jl +++ b/src/operation/decision_model.jl @@ -16,7 +16,7 @@ struct GenericOpProblem <: DefaultDecisionProblem end jump_model::Union{Nothing, JuMP.Model}=nothing; kwargs...) where {M<:DecisionProblem} -Builds the optimization problem of type M with the specific system and template. +Build the optimization problem of type M with the specific system and template. # Arguments @@ -136,7 +136,7 @@ function DecisionModel{M}( end """ -Builds the optimization problem of type M with the specific system and template +Build the optimization problem of type M with the specific system and template # Arguments diff --git a/src/operation/emulation_model.jl b/src/operation/emulation_model.jl index 2186f8de4d..0f27b8ddc4 100644 --- a/src/operation/emulation_model.jl +++ b/src/operation/emulation_model.jl @@ -16,7 +16,7 @@ struct GenericEmulationProblem <: DefaultEmulationProblem end jump_model::Union{Nothing, JuMP.Model}=nothing; kwargs...) where {M<:EmulationProblem} -Builds the optimization problem of type M with the specific system and template. +Build the optimization problem of type M with the specific system and template. # Arguments @@ -126,7 +126,7 @@ function EmulationModel{M}( end """ -Builds the optimization problem of type M with the specific system and template +Build the optimization problem of type M with the specific system and template # Arguments From 271f26b9593153b8e4ab16e43282ff181a3394f6 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 9 Aug 2023 13:47:46 -0600 Subject: [PATCH 338/370] export the serialize functions for the problems --- src/PowerSimulations.jl | 1 + src/operation/operation_model_interface.jl | 8 ++++++++ src/utils/jump_utils.jl | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 3240de1f95..38f0e93b71 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -181,6 +181,7 @@ export get_realized_timestamps export get_problem_base_power export get_objective_value export read_optimizer_stats +export serialize_optimization_model ## Utils Exports export get_all_constraint_index diff --git a/src/operation/operation_model_interface.jl b/src/operation/operation_model_interface.jl index 53aae2f0fb..75ccd2bd56 100644 --- a/src/operation/operation_model_interface.jl +++ b/src/operation/operation_model_interface.jl @@ -393,3 +393,11 @@ function list_all_keys(x::OperationModel) keys(get_data_field(get_store(x), f)) for f in STORE_CONTAINERS ) end + +function serialize_optimization_model(model::OperationModel, save_path::String) + serialize_jump_optimization_model( + get_optimization_container(model), + save_path, + ) + return +end diff --git a/src/utils/jump_utils.jl b/src/utils/jump_utils.jl index 187aa7b3e7..5f1b2aa2ce 100644 --- a/src/utils/jump_utils.jl +++ b/src/utils/jump_utils.jl @@ -300,7 +300,7 @@ end """ Exports the JuMP object in MathOptFormat """ -function serialize_optimization_model(jump_model::JuMP.Model, save_path::String) +function serialize_jump_optimization_model(jump_model::JuMP.Model, save_path::String) MOF_model = MOPFM(; format = MOI.FileFormats.FORMAT_MOF) MOI.copy_to(MOF_model, JuMP.backend(jump_model)) MOI.write_to_file(MOF_model, save_path) From 424b366a7240e8d710abe7728c0c1a7d25ea9452 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 9 Aug 2023 13:48:07 -0600 Subject: [PATCH 339/370] some updates to definitions --- docs/src/modeler_guide/definitions.md | 4 +++- docs/src/tutorials/decision_problem.md | 15 ++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/src/modeler_guide/definitions.md b/docs/src/modeler_guide/definitions.md index 77a91065e0..8a4946f85f 100644 --- a/docs/src/modeler_guide/definitions.md +++ b/docs/src/modeler_guide/definitions.md @@ -2,7 +2,9 @@ ## D -* *Decision Problem*: A decision problem calculates the desired system operation based on forecasts of uncertain inputs and information about the state of the system. The output of a decision problem represents the policies used to drive the set-points of the system's devices, like generators or switches, and depends on the purpose of the problem. +* *Decision Problem*: A decision problem calculates the desired system operation based on forecasts of uncertain inputs and information about the state of the system. The output of a decision problem represents the policies used to drive the set-points of the system's devices, like generators or switches, and depends on the purpose of the problem. See the [Decision Model Tutorial](op_problem_tutorial) to learn more about solving individual problems. + +* *Device Formulation*: The model of a device that is incorporated into a large system optimization models. For instance, the storage device model used inside of a Unit Commitment (UC) problem. A device model needs to follow some requirements to be integrated into operation problems. ## E diff --git a/docs/src/tutorials/decision_problem.md b/docs/src/tutorials/decision_problem.md index 584a986811..896e105639 100644 --- a/docs/src/tutorials/decision_problem.md +++ b/docs/src/tutorials/decision_problem.md @@ -19,8 +19,9 @@ using HiGHS # solver ## Data -This data depends upon the [RTS-GMLC](https://github.com/gridmod/rts-gmlc) dataset. Let's -use [PowerSystemCaseBuilder.jl](https://github.com/nrel-sienna/powersystemcasebuilder.jl) to download and build a `System`. +!!! 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 Documentation](https://nrel-sienna.github.io/PowerSystems.jl/stable/tutorials/powersystembuilder/) ```@example op_problem sys = build_system(PSISystems, "modified_RTS_GMLC_DA_sys") @@ -40,8 +41,8 @@ and the subtypes of `AbstractDeviceFormulation`. PowerSimulations has a variety each dispatching to different methods for populating optimization problem objectives, variables, and constraints. Documentation on the formulation options for various devices can be found in the [formulation library docs](https://nrel-sienna.github.io/PowerSimulations.jl/latest/formulation_library/General/#formulation_library) - ### Branch Formulations + Here is an example of relatively standard branch formulations. Other formulations allow for selective enforcement of transmission limits and greater control on transformer settings. @@ -117,13 +118,9 @@ build!(problem, output_dir = mktempdir()) ``` !!! tip - The principal component of the `DecisionModel` is the JuMP model. For small problems, you can inspect it by simply printing it to the screen: - ```julia jump_model - print(PowerSimulations.get_jump_model(problem)) - ``` - For anything of reasonable size, that will be unmanageable. But you can print to a file: + The principal component of the `DecisionModel` is the JuMP model. But you can print to a file: ```julia - f = open("testmodel.txt","w"); print(f,PowerSimulations.get_jump_model(problem)); close(f) + serialize_optimization_model(problem, save_path) ``` ### Solve an `DecisionModel` From 88230ed7e6286f16715dbc8f48f985f3d5330f12 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 9 Aug 2023 15:25:58 -0600 Subject: [PATCH 340/370] update to decision models docs --- docs/src/tutorials/decision_problem.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/src/tutorials/decision_problem.md b/docs/src/tutorials/decision_problem.md index 896e105639..eaa60e6b0b 100644 --- a/docs/src/tutorials/decision_problem.md +++ b/docs/src/tutorials/decision_problem.md @@ -118,10 +118,11 @@ build!(problem, output_dir = mktempdir()) ``` !!! tip - The principal component of the `DecisionModel` is the JuMP model. But you can print to a file: + The principal component of the `DecisionModel` is the JuMP model. But you can serialize to a file using the following command: ```julia serialize_optimization_model(problem, save_path) ``` + Keep in mind that if the setting "store_variable_names" is set to `False` then the file won't show the model's names. ### Solve an `DecisionModel` From 8849be668aadf5d96a850ea8581051c428ed16f3 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 14 Aug 2023 09:07:42 -0600 Subject: [PATCH 341/370] docs improvements --- .../structure_of_operation_problem.md | 40 ++++++++ .../src/tutorials/adding_new_problem_model.md | 91 +++++++++++++++++-- 2 files changed, 123 insertions(+), 8 deletions(-) diff --git a/docs/src/model_developer_guide/structure_of_operation_problem.md b/docs/src/model_developer_guide/structure_of_operation_problem.md index 202bbe0cb0..8b793d7948 100644 --- a/docs/src/model_developer_guide/structure_of_operation_problem.md +++ b/docs/src/model_developer_guide/structure_of_operation_problem.md @@ -8,3 +8,43 @@ and register the constraints, variables and other optimization objects into Powe !!! info The requirements for the simulation of Power Systems operations are more strict than solving an optimization problem once with just `JuMP.jl`. The requirements imposed by `PowerSimulations.jl` to integrate your models in a simulation are designed to help with other complex operations that go beyond `JuMP.jl` scope. + +!!! warning + All the code in this page is considered "pseudo-code". Copy-paste will likely not work out of the box. You need to develop the internals of the functions correctly for the examples below to work. + +## Registering a variable in the model + +To register a variable in the model, the developer must first allocate the container into the +optimization container and then populate it. For example, it require start the build function as follows: + +!!! info + We recommend calling `import PowerSimulations` and defining the constant `CONST PSI = PowerSimulations` to + make it easier to read the code and determine which package is responsible for defining the functions. + +```julia + function PSI.build_model!(model::PSI.DecisionModel{MyCustomModel}) + container = PSI.get_optimization_container(model) + PSI.set_time_steps!(container, 1:24) + + # Create the container for the variable + variable = PSI.add_variable_container!( + container, + PSI.ActivePowerVariable(), # <- This variable is defined in PowerSimulations but the user can define their own + PSY.ThermalGeneration, # <- Device type for the variable. Can be from PSY or custom defined + devices_names, # <- First container dimension + time_steps, # <- Second container dimension + ) + + # Iterate over the devices and time to store the JuMP variables into the container. + for t in time_steps, d in devices + name = PSY.get_name(d) + variable[name, t] = JuMP.@variable(get_jump_model(container)) + # It is possible to use PSY getter functions to retrieve data from the generators + # Any other variable property can be specified inside this loop. + JuMP.set_upper_bound(variable[name, t], UB_DATA) # <- Optional + JuMP.set_lower_bound(variable[name, t], LB_DATA) # <- Optional + end + + return + end +``` diff --git a/docs/src/tutorials/adding_new_problem_model.md b/docs/src/tutorials/adding_new_problem_model.md index 795a3f1111..ab81f6ed04 100644 --- a/docs/src/tutorials/adding_new_problem_model.md +++ b/docs/src/tutorials/adding_new_problem_model.md @@ -68,18 +68,93 @@ These methods can be defined optionally for your problem. By default for problem ### How to develop your `build_model!` function +#### Registering a variable in the model +To register a variable in the model, the developer must first allocate the container into the +optimization container and then populate it. For example, it require start the build function as follows: + +!!! info + We recommend calling `import PowerSimulations` and defining the constant `CONST PSI = PowerSimulations` to + make it easier to read the code and determine which package is responsible for defining the functions. ```julia -function PSI.build_model!(model::PSI.DecisionModel{MyCustomDecisionProblem}) - container = PSI.get_optimization_container(model) - PSI.set_time_steps!(container, 1:24) # <- Mandatory - system = PSI.get_system(model) + function PSI.build_model!(model::PSI.DecisionModel{MyCustomDecisionProblem}) + container = PSI.get_optimization_container(model) + time_steps = 1:24 + PSI.set_time_steps!(container, time_steps) + system = PSI.get_system(model) + + thermal_gens = PSY.get_components(PSY.ThermalStandard, system) + thermal_gens_names = PSY.get_name.(thermal_gens) + + # Create the container for the variable + variable = PSI.add_variable_container!( + container, + PSI.ActivePowerVariable(), # <- This variable is defined in PowerSimulations but the user can define their own + PSY.ThermalGeneration, # <- Device type for the variable. Can be from PSY or custom defined + thermal_gens_names, # <- First container dimension + time_steps, # <- Second container dimension + ) + + # Iterate over the devices and time to store the JuMP variables into the container. + for t in time_steps, d in thermal_gens_names + name = PSY.get_name(d) + variable[name, t] = JuMP.@variable(get_jump_model(container)) + # It is possible to use PSY getter functions to retrieve data from the generators + JuMP.set_upper_bound(variable[name, t], UB_DATA) # <- Optional + JuMP.set_lower_bound(variable[name, t], LB_DATA) # <- Optional + end + + # Add More Variables..... + + return + end +``` +#### Registering a constraint in the model +A similar pattern is used to add constraints to the model, in this example the field `meta` is used +to avoid creating unnecessary duplicate constraint types. For instance to reflect upper_bound and lower_bound or upwards and downwards constraints. Meta can take any string value except for the `_` character. - update_objective_function!(container) # <- Mandatory -end +```julia + function PSI.build_model!(model::PSI.DecisionModel{MyCustomDecisionProblem}) + container = PSI.get_optimization_container(model) + time_steps = 1:24 + PSI.set_time_steps!(container, time_steps) + system = PSI.get_system(model) + + # VARIABLE ADDITION CODE + + # Constraint additions + con_ub = PSI.add_constraints_container!( + container, + PSI.RangeLimitConstraint(), # <- Constraint Type defined by PSI or your own + PSY.ThermalGeneration, # <- Device type for variable. Can be PSY or custom + thermal_gens_names, # <- First container dimension + time_steps; # <- Second container dimension + meta = "ub" # <- meta allows to reuse a constraint definition for similar constraints. It only requires to be a string + ) + + con_lb = PSI.add_constraints_container!( + container, + PSI.RangeLimitConstraint(), + PSY.ThermalGeneration, + thermal_gens_names, # <- First container dimension + time_steps; # <- Second container dimension + meta = "lb" # <- meta allows to reuse a constraint definition for similar constraints. It only requires to be a string + ) + + # Retrieve a relevant variable from the container if not defined in + variable = PSI.get_variable(container, PSI.ActivePowerVariable(), PSY.ThermalGeneration) + for device in devices, t in time_steps + ci_name = PSY.get_name(device) + limits = get_min_max_limits(device) # depends on constraint type and formulation type + con_ub[ci_name, t] = + JuMP.@constraint(get_jump_model(container), variable[ci_name, t] >= limits.min) + con_lb[ci_name, t] = + JuMP.@constraint(get_jump_model(container), variable[ci_name, t] >= limits.min) + end + + return + end ``` - -## Emulation Problem From 223e3ecc85f0cbcb4e2e2e5737f313b0daeaaf78 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 14 Aug 2023 09:10:08 -0600 Subject: [PATCH 342/370] other improvements --- src/PowerSimulations.jl | 3 --- src/core/constraints.jl | 9 ++------- src/core/optimization_container.jl | 2 +- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 38f0e93b71..d801d66338 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -276,10 +276,7 @@ export FlowReactivePowerToFromConstraint export FrequencyResponseConstraint export HVDCPowerBalance export HVDCLosses -export InflowRangeConstraint export InputActivePowerVariableLimitsConstraint -export InputPowerRangeConstraint -export InterConnectionLimitConstraint export NetworkFlowConstraint export NodalBalanceActiveConstraint export NodalBalanceReactiveConstraint diff --git a/src/core/constraints.jl b/src/core/constraints.jl index 47a2043ef9..ac0f75957e 100644 --- a/src/core/constraints.jl +++ b/src/core/constraints.jl @@ -26,8 +26,6 @@ end Base.convert(::Type{ConstraintKey}, name::Symbol) = ConstraintKey(decode_symbol(name)...) struct AbsoluteValueConstraint <: ConstraintType end -struct ActiveConstraint <: ConstraintType end -struct ActiveRangeConstraint <: ConstraintType end #not being used struct ActiveRangeICConstraint <: ConstraintType end struct AreaDispatchBalanceConstraint <: ConstraintType end struct AreaParticipationAssignmentConstraint <: ConstraintType end @@ -56,9 +54,6 @@ struct FlowReactivePowerFromToConstraint <: ConstraintType end #not being used struct FlowReactivePowerToFromConstraint <: ConstraintType end #not being used struct HVDCPowerBalance <: ConstraintType end struct FrequencyResponseConstraint <: ConstraintType end -struct InflowRangeConstraint <: ConstraintType end #not being used -struct InputPowerRangeConstraint <: ConstraintType end #not being used -struct InterConnectionLimitConstraint <: ConstraintType end #not being used struct NetworkFlowConstraint <: ConstraintType end struct NodalBalanceActiveConstraint <: ConstraintType end struct NodalBalanceReactiveConstraint <: ConstraintType end @@ -75,8 +70,8 @@ struct RegulationLimitsConstraint <: ConstraintType end struct RequirementConstraint <: ConstraintType end struct ReserveEnergyCoverageConstraint <: ConstraintType end struct ReservePowerConstraint <: ConstraintType end -struct SACEPIDAreaConstraint <: ConstraintType end #not being used -struct StartTypeConstraint <: ConstraintType end #not being used +struct SACEPIDAreaConstraint <: ConstraintType end +struct StartTypeConstraint <: ConstraintType end struct StartupInitialConditionConstraint <: ConstraintType end struct StartupTimeLimitTemperatureConstraint <: ConstraintType end struct PhaseAngleControlLimit <: ConstraintType end diff --git a/src/core/optimization_container.jl b/src/core/optimization_container.jl index eb0cb5b93c..769d78a1ea 100644 --- a/src/core/optimization_container.jl +++ b/src/core/optimization_container.jl @@ -699,7 +699,7 @@ end Exports the OpModel JuMP object in MathOptFormat """ function serialize_optimization_model(container::OptimizationContainer, save_path::String) - serialize_optimization_model(get_jump_model(container), save_path) + serialize_jump_optimization_model(get_jump_model(container), save_path) return end From c20f4ddf7e5dd7c15778df6d84337bd922277730 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Mon, 14 Aug 2023 09:19:32 -0600 Subject: [PATCH 343/370] remove ActiveConstraint references --- docs/src/api/PowerSimulations.md | 1 - src/PowerSimulations.jl | 1 - 2 files changed, 2 deletions(-) diff --git a/docs/src/api/PowerSimulations.md b/docs/src/api/PowerSimulations.md index 2f8d8e47b4..c038a7d6c1 100644 --- a/docs/src/api/PowerSimulations.md +++ b/docs/src/api/PowerSimulations.md @@ -179,7 +179,6 @@ PieceWiseLinearCostConstraint ### Network Constraints ```@docs -ActiveConstraint AreaDispatchBalanceConstraint AreaParticipationAssignmentConstraint BalanceAuxConstraint diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index d801d66338..d142923b95 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -245,7 +245,6 @@ export EnergyOutput # Constraints export AbsoluteValueConstraint -export ActiveConstraint export ActivePowerVariableLimitsConstraint export ActivePowerVariableTimeSeriesLimitsConstraint export ActiveRangeICConstraint From 944d7c17047d8e5ccdfdaf7dea33350d357bff3d Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 6 Sep 2023 10:20:31 -0600 Subject: [PATCH 344/370] Update PowerSimulations.jl --- src/PowerSimulations.jl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index f8c7d4c1d8..43e2aa2ff4 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -69,10 +69,6 @@ export ThermalCompactDispatch export DeviceLimitedRegulation export ReserveLimitedRegulation -###### Hydro ####### -# export HydroDispatchRunOfRiver -export HydroCommitmentRunOfRiver - # feedforward models export UpperBoundFeedforward export LowerBoundFeedforward From 0a9ed84bb9f1da9a1090688cbe269107cee699f0 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 6 Sep 2023 10:21:13 -0600 Subject: [PATCH 345/370] Update formulations.jl --- src/core/formulations.jl | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 4fefb8d6f1..73e801cdf6 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -72,21 +72,6 @@ Formulation type to enable (continuous) load interruption dispatch """ struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end -############################ Hydro Generation Formulations ################################# -# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end -# abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end -# abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end - -# """ -# Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` -# """ -# struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end - -# """ -# Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` -# """ -# struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end - ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end struct ReserveLimitedRegulation <: AbstractRegulationFormulation end From 8fe2d27450cbca29cbabcd2b6d71f1589ed4e149 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 6 Sep 2023 10:21:33 -0600 Subject: [PATCH 346/370] Delete src/devices_models/device_constructors/hydrogeneration_constructor.jl --- .../hydrogeneration_constructor.jl | 468 ------------------ 1 file changed, 468 deletions(-) delete mode 100644 src/devices_models/device_constructors/hydrogeneration_constructor.jl diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl deleted file mode 100644 index c1ed64385f..0000000000 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ /dev/null @@ -1,468 +0,0 @@ -# """ -# Construct model for HydroGen with FixedOutput Formulation -# """ -# function construct_device!( -# container::OptimizationContainer, -# sys::PSY.System, -# ::ArgumentConstructStage, -# model::DeviceModel{H, FixedOutput}, -# network_model::NetworkModel{S}, -# ) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} -# devices = -# get_available_components(H, sys, get_attribute(model, "filter_function")) -# -# add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) -# add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) -# -# # Expression -# add_to_expression!( -# container, -# ActivePowerBalance, -# ActivePowerTimeSeriesParameter, -# devices, -# model, -# network_model, -# ) -# add_to_expression!( -# container, -# ReactivePowerBalance, -# ReactivePowerTimeSeriesParameter, -# devices, -# model, -# network_model, -# ) -# return -# end -# -# function construct_device!( -# ::OptimizationContainer, -# ::PSY.System, -# ::ModelConstructStage, -# ::DeviceModel{H, FixedOutput}, -# network_model::NetworkModel{S}, -# ) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} -# # FixedOutput doesn't add any constraints to the model. This function covers -# # AbstractPowerModel and AbstractActivePowerModel -# return -# end -# -# function construct_device!( -# container::OptimizationContainer, -# sys::PSY.System, -# ::ArgumentConstructStage, -# model::DeviceModel{H, FixedOutput}, -# network_model::NetworkModel{S}, -# ) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} -# devices = -# get_available_components(H, sys, get_attribute(model, "filter_function")) -# -# add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) -# -# # Expression -# add_to_expression!( -# container, -# ActivePowerBalance, -# ActivePowerTimeSeriesParameter, -# devices, -# model, -# network_model, -# ) -# return -# end -# -# """ -# Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation -# """ -# function construct_device!( -# container::OptimizationContainer, -# sys::PSY.System, -# ::ArgumentConstructStage, -# model::DeviceModel{H, D}, -# network_model::NetworkModel{S}, -# ) where { -# H <: PSY.HydroGen, -# D <: AbstractHydroDispatchFormulation, -# S <: PM.AbstractPowerModel, -# } -# devices = -# get_available_components(H, sys, get_attribute(model, "filter_function")) -# -# add_variables!(container, ActivePowerVariable, devices, D()) -# add_variables!(container, ReactivePowerVariable, devices, D()) -# add_variables!(container, EnergyOutput, devices, D()) -# add_to_expression!( -# container, -# ActivePowerBalance, -# ActivePowerVariable, -# devices, -# model, -# network_model, -# ) -# add_to_expression!( -# container, -# ReactivePowerBalance, -# ReactivePowerVariable, -# devices, -# model, -# network_model, -# ) -# -# add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) -# -# add_expressions!(container, ProductionCostExpression, devices, model) -# -# add_to_expression!( -# container, -# ActivePowerRangeExpressionLB, -# ActivePowerVariable, -# devices, -# model, -# network_model, -# ) -# add_to_expression!( -# container, -# ActivePowerRangeExpressionUB, -# ActivePowerVariable, -# devices, -# model, -# network_model, -# ) -# -# add_feedforward_arguments!(container, model, devices) -# return -# end -# -# function construct_device!( -# container::OptimizationContainer, -# sys::PSY.System, -# ::ModelConstructStage, -# model::DeviceModel{H, D}, -# network_model::NetworkModel{S}, -# ) where { -# H <: PSY.HydroGen, -# D <: AbstractHydroDispatchFormulation, -# S <: PM.AbstractPowerModel, -# } -# devices = -# get_available_components(H, sys, get_attribute(model, "filter_function")) -# -# add_constraints!( -# container, -# ActivePowerVariableLimitsConstraint, -# ActivePowerRangeExpressionLB, -# devices, -# model, -# network_model, -# ) -# add_constraints!( -# container, -# ActivePowerVariableLimitsConstraint, -# ActivePowerRangeExpressionUB, -# devices, -# model, -# network_model, -# ) -# -# add_constraints!( -# container, -# ReactivePowerVariableLimitsConstraint, -# ReactivePowerVariable, -# devices, -# model, -# network_model, -# ) -# add_feedforward_constraints!(container, model, devices) -# -# objective_function!(container, devices, model, S) -# add_constraint_dual!(container, sys, model) -# -# return -# end -# -# """ -# Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation -# with only Active Power. -# """ -# function construct_device!( -# container::OptimizationContainer, -# sys::PSY.System, -# ::ArgumentConstructStage, -# model::DeviceModel{H, D}, -# network_model::NetworkModel{S}, -# ) where { -# H <: PSY.HydroGen, -# D <: AbstractHydroDispatchFormulation, -# S <: PM.AbstractActivePowerModel, -# } -# devices = -# get_available_components(H, sys, get_attribute(model, "filter_function")) -# -# add_variables!(container, ActivePowerVariable, devices, D()) -# add_variables!(container, EnergyOutput, devices, D()) -# add_to_expression!( -# container, -# ActivePowerBalance, -# ActivePowerVariable, -# devices, -# model, -# network_model, -# ) -# -# add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) -# add_to_expression!( -# container, -# ActivePowerRangeExpressionLB, -# ActivePowerVariable, -# devices, -# model, -# network_model, -# ) -# add_to_expression!( -# container, -# ActivePowerRangeExpressionUB, -# ActivePowerVariable, -# devices, -# model, -# network_model, -# ) -# -# add_expressions!(container, ProductionCostExpression, devices, model) -# -# add_feedforward_arguments!(container, model, devices) -# return -# end -# -# function construct_device!( -# container::OptimizationContainer, -# sys::PSY.System, -# ::ModelConstructStage, -# model::DeviceModel{H, D}, -# network_model::NetworkModel{S}, -# ) where { -# H <: PSY.HydroGen, -# D <: AbstractHydroDispatchFormulation, -# S <: PM.AbstractActivePowerModel, -# } -# devices = -# get_available_components(H, sys, get_attribute(model, "filter_function")) -# -# add_constraints!( -# container, -# ActivePowerVariableLimitsConstraint, -# ActivePowerRangeExpressionLB, -# devices, -# model, -# network_model, -# ) -# add_constraints!( -# container, -# ActivePowerVariableLimitsConstraint, -# ActivePowerRangeExpressionUB, -# devices, -# model, -# network_model, -# ) -# -# add_feedforward_constraints!(container, model, devices) -# -# objective_function!(container, devices, model, S) -# -# add_constraint_dual!(container, sys, model) -# return -# end -# -# """ -# Construct model for HydroGen with RunOfRiver Commitment Formulation -# """ -# function construct_device!( -# container::OptimizationContainer, -# sys::PSY.System, -# ::ArgumentConstructStage, -# model::DeviceModel{H, D}, -# network_model::NetworkModel{S}, -# ) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} -# devices = -# get_available_components(H, sys, get_attribute(model, "filter_function")) -# -# add_variables!(container, ActivePowerVariable, devices, D()) -# add_variables!(container, ReactivePowerVariable, devices, D()) -# add_variables!(container, OnVariable, devices, D()) -# add_variables!(container, EnergyOutput, devices, D()) -# add_to_expression!( -# container, -# ActivePowerBalance, -# ActivePowerVariable, -# devices, -# model, -# network_model, -# ) -# -# add_to_expression!( -# container, -# ReactivePowerBalance, -# ReactivePowerVariable, -# devices, -# model, -# network_model, -# ) -# -# add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) -# -# add_expressions!(container, ProductionCostExpression, devices, model) -# -# add_to_expression!( -# container, -# ActivePowerRangeExpressionLB, -# ActivePowerVariable, -# devices, -# model, -# network_model, -# ) -# add_to_expression!( -# container, -# ActivePowerRangeExpressionUB, -# ActivePowerVariable, -# devices, -# model, -# network_model, -# ) -# add_feedforward_arguments!(container, model, devices) -# return -# end -# -# function construct_device!( -# container::OptimizationContainer, -# sys::PSY.System, -# ::ModelConstructStage, -# model::DeviceModel{H, D}, -# network_model::NetworkModel{S}, -# ) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} -# devices = -# get_available_components(H, sys, get_attribute(model, "filter_function")) -# -# add_constraints!( -# container, -# ActivePowerVariableLimitsConstraint, -# ActivePowerRangeExpressionLB, -# devices, -# model, -# network_model, -# ) -# add_constraints!( -# container, -# ActivePowerVariableLimitsConstraint, -# ActivePowerRangeExpressionUB, -# devices, -# model, -# network_model, -# ) -# -# add_constraints!( -# container, -# ReactivePowerVariableLimitsConstraint, -# ReactivePowerVariable, -# devices, -# model, -# network_model, -# ) -# -# add_feedforward_constraints!(container, model, devices) -# -# objective_function!(container, devices, model, S) -# -# add_constraint_dual!(container, sys, model) -# return -# end -# -# """ -# Construct model for HydroGen with RunOfRiver Commitment Formulation -# with only Active Power. -# """ -# function construct_device!( -# container::OptimizationContainer, -# sys::PSY.System, -# ::ArgumentConstructStage, -# model::DeviceModel{H, D}, -# network_model::NetworkModel{S}, -# ) where { -# H <: PSY.HydroGen, -# D <: HydroCommitmentRunOfRiver, -# S <: PM.AbstractActivePowerModel, -# } -# devices = -# get_available_components(H, sys, get_attribute(model, "filter_function")) -# -# add_variables!(container, ActivePowerVariable, devices, D()) -# add_variables!(container, OnVariable, devices, D()) -# add_variables!(container, EnergyOutput, devices, D()) -# add_to_expression!( -# container, -# ActivePowerBalance, -# ActivePowerVariable, -# devices, -# model, -# network_model, -# ) -# -# add_expressions!(container, ProductionCostExpression, devices, model) -# -# add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) -# add_to_expression!( -# container, -# ActivePowerRangeExpressionLB, -# ActivePowerVariable, -# devices, -# model, -# network_model, -# ) -# add_to_expression!( -# container, -# ActivePowerRangeExpressionUB, -# ActivePowerVariable, -# devices, -# model, -# network_model, -# ) -# -# add_feedforward_arguments!(container, model, devices) -# return -# end -# -# function construct_device!( -# container::OptimizationContainer, -# sys::PSY.System, -# ::ModelConstructStage, -# model::DeviceModel{H, D}, -# network_model::NetworkModel{S}, -# ) where { -# H <: PSY.HydroGen, -# D <: HydroCommitmentRunOfRiver, -# S <: PM.AbstractActivePowerModel, -# } -# devices = -# get_available_components(H, sys, get_attribute(model, "filter_function")) -# -# add_constraints!( -# container, -# ActivePowerVariableLimitsConstraint, -# ActivePowerRangeExpressionLB, -# devices, -# model, -# network_model, -# ) -# add_constraints!( -# container, -# ActivePowerVariableLimitsConstraint, -# ActivePowerRangeExpressionUB, -# devices, -# model, -# network_model, -# ) -# -# add_feedforward_constraints!(container, model, devices) -# -# objective_function!(container, devices, model, S) -# -# add_constraint_dual!(container, sys, model) -# return -# end From 87cd68207fd83cf87e21ed3a6e288e7e1f4af442 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 6 Sep 2023 10:21:51 -0600 Subject: [PATCH 347/370] Delete src/devices_models/devices/hydro_generation.jl --- .../devices/hydro_generation.jl | 296 ------------------ 1 file changed, 296 deletions(-) delete mode 100644 src/devices_models/devices/hydro_generation.jl diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl deleted file mode 100644 index 4db297382a..0000000000 --- a/src/devices_models/devices/hydro_generation.jl +++ /dev/null @@ -1,296 +0,0 @@ -# #! format: off -# requires_initialization(::AbstractHydroFormulation) = false -# requires_initialization(::AbstractHydroUnitCommitment) = true -# -# #DELETE -# # get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 -# get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB -# get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB -# -# ########################### ActivePowerVariable, HydroGen ################################# -# get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -# get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -# get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min -# get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 -# get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max -# -# ############## ActivePowerVariable, HydroDispatchRunOfRiver #################### -# get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 -# -# ############## ReactivePowerVariable, HydroGen #################### -# get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -# get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power(d) -# get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).min -# get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).max -# -# ############## OnVariable, HydroGen #################### -# get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true -# get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 -# -# ########################### Parameter related set functions ################################ -# get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) -# get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) -# -# get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -# get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -# get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max -# get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min -# -# #################### Initial Conditions for models ############### -# initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) -# initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -# initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -# initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() -# initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 -# initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -# initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) -# initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -# -# ########################Objective Function################################################## -# proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 -# proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) -# -# objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -# objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -# objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -# -# sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE -# sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE -# -# variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 -# variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) -# variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) -# -# #! format: on -# -# function get_initial_conditions_device_model( -# ::OperationModel, -# model::DeviceModel{T, <:AbstractHydroFormulation}, -# ) where {T <: PSY.HydroEnergyReservoir} -# return model -# end -# -# function get_initial_conditions_device_model( -# ::OperationModel, -# ::DeviceModel{T, <:AbstractHydroFormulation}, -# ) where {T <: PSY.HydroDispatch} -# return DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver) -# end -# -# # DELETE -# # function get_default_time_series_names( -# # ::Type{<:PSY.HydroGen}, -# # ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, -# # ) -# # return Dict{Type{<:TimeSeriesParameter}, String}( -# # ActivePowerTimeSeriesParameter => "max_active_power", -# # ReactivePowerTimeSeriesParameter => "max_active_power", -# # ) -# # end -# -# # DELETE -# # function get_default_attributes( -# # ::Type{T}, -# # ::Type{D}, -# # ) where {T <: PSY.HydroGen, D <: Union{FixedOutput, AbstractHydroFormulation}} -# # return Dict{String, Any}("reservation" => false) -# # end -# -# """ -# Time series constraints -# """ -# function add_constraints!( -# container::OptimizationContainer, -# T::Type{ActivePowerVariableLimitsConstraint}, -# U::Type{<:Union{VariableType, ExpressionType}}, -# devices::IS.FlattenIteratorWrapper{V}, -# model::DeviceModel{V, W}, -# ::NetworkModel{X}, -# ) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} -# if !has_semicontinuous_feedforward(model, U) -# add_range_constraints!(container, T, U, devices, model, X) -# end -# add_parameterized_upper_bound_range_constraints( -# container, -# ActivePowerVariableTimeSeriesLimitsConstraint, -# U, -# ActivePowerTimeSeriesParameter, -# devices, -# model, -# X, -# ) -# return -# end -# -# function add_constraints!( -# container::OptimizationContainer, -# T::Type{ActivePowerVariableLimitsConstraint}, -# U::Type{<:RangeConstraintLBExpressions}, -# devices::IS.FlattenIteratorWrapper{V}, -# model::DeviceModel{V, W}, -# ::NetworkModel{X}, -# ) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} -# if !has_semicontinuous_feedforward(model, U) -# add_range_constraints!(container, T, U, devices, model, X) -# end -# return -# end -# -# """ -# Add semicontinuous range constraints for Hydro Unit Commitment formulation -# """ -# function add_constraints!( -# container::OptimizationContainer, -# T::Type{ActivePowerVariableLimitsConstraint}, -# U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, -# devices::IS.FlattenIteratorWrapper{V}, -# model::DeviceModel{V, W}, -# ::NetworkModel{X}, -# ) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} -# add_semicontinuous_range_constraints!(container, T, U, devices, model, X) -# return -# end -# -# function add_constraints!( -# container::OptimizationContainer, -# T::Type{ActivePowerVariableLimitsConstraint}, -# U::Type{<:Union{VariableType, ExpressionType}}, -# devices::IS.FlattenIteratorWrapper{V}, -# model::DeviceModel{V, W}, -# ::NetworkModel{X}, -# ) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} -# add_semicontinuous_range_constraints!(container, T, U, devices, model, X) -# add_parameterized_upper_bound_range_constraints( -# container, -# ActivePowerVariableTimeSeriesLimitsConstraint, -# U, -# ActivePowerTimeSeriesParameter, -# devices, -# model, -# X, -# ) -# return -# end -# -# """ -# Min and max reactive Power Variable limits -# """ -# function get_min_max_limits( -# x::PSY.HydroGen, -# ::Type{<:ReactivePowerVariableLimitsConstraint}, -# ::Type{<:AbstractHydroFormulation}, -# ) -# return PSY.get_reactive_power_limits(x) -# end -# -# """ -# Min and max active Power Variable limits -# """ -# function get_min_max_limits( -# x::PSY.HydroGen, -# ::Type{<:ActivePowerVariableLimitsConstraint}, -# ::Type{<:AbstractHydroFormulation}, -# ) -# return PSY.get_active_power_limits(x) -# end -# -# function get_min_max_limits( -# x::PSY.HydroGen, -# ::Type{<:ActivePowerVariableLimitsConstraint}, -# ::Type{HydroDispatchRunOfRiver}, -# ) -# return (min = 0.0, max = PSY.get_max_active_power(x)) -# end -# -# """ -# Add power variable limits constraints for hydro unit commitment formulation -# """ -# function add_constraints!( -# container::OptimizationContainer, -# T::Type{<:PowerVariableLimitsConstraint}, -# U::Type{<:Union{VariableType, ExpressionType}}, -# devices::IS.FlattenIteratorWrapper{V}, -# model::DeviceModel{V, W}, -# ::NetworkModel{X}, -# ) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} -# add_semicontinuous_range_constraints!(container, T, U, devices, model, X) -# return -# end -# -# """ -# Add power variable limits constraints for hydro dispatch formulation -# """ -# function add_constraints!( -# container::OptimizationContainer, -# T::Type{<:PowerVariableLimitsConstraint}, -# U::Type{<:Union{VariableType, ExpressionType}}, -# devices::IS.FlattenIteratorWrapper{V}, -# model::DeviceModel{V, W}, -# ::NetworkModel{X}, -# ) where { -# V <: PSY.HydroGen, -# W <: AbstractHydroDispatchFormulation, -# X <: PM.AbstractPowerModel, -# } -# if !has_semicontinuous_feedforward(model, U) -# add_range_constraints!(container, T, U, devices, model, X) -# end -# return -# end -# -# ##################################### Auxillary Variables ############################ -# function _calculate_aux_variable_value!( -# container::OptimizationContainer, -# ::AuxVarKey{EnergyOutput, T}, -# system::PSY.System, -# p_variable_results::JuMPVariableArray, -# ) where {T <: PSY.HydroGen} -# devices = axes(p_variable_results, 1) -# time_steps = get_time_steps(container) -# resolution = get_resolution(container) -# fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR -# aux_variable_container = get_aux_variable(container, EnergyOutput(), T) -# for name in devices, t in time_steps -# aux_variable_container[name, t] = -# jump_value(p_variable_results[name, t]) * fraction_of_hour -# end -# -# return -# end -# -# function calculate_aux_variable_value!( -# container::OptimizationContainer, -# aux_key::AuxVarKey{EnergyOutput, T}, -# system::PSY.System, -# ) where {T <: PSY.HydroGen} -# p_variable_results = get_variable(container, ActivePowerVariable(), T) -# _calculate_aux_variable_value!( -# container, -# aux_key, -# system, -# p_variable_results, -# ) -# return -# end -# -# ##################################### Hydro generation cost ############################ -# function objective_function!( -# container::OptimizationContainer, -# devices::IS.FlattenIteratorWrapper{T}, -# ::DeviceModel{T, U}, -# ::Type{<:PM.AbstractPowerModel}, -# ) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} -# add_variable_cost!(container, ActivePowerVariable(), devices, U()) -# add_proportional_cost!(container, OnVariable(), devices, U()) -# return -# end -# -# function objective_function!( -# container::OptimizationContainer, -# devices::IS.FlattenIteratorWrapper{T}, -# ::DeviceModel{T, U}, -# ::Type{<:PM.AbstractPowerModel}, -# ) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} -# add_variable_cost!(container, ActivePowerVariable(), devices, U()) -# return -# end From ac9cb69517ef487926d32d6c90cb8826c7177554 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 6 Sep 2023 10:22:44 -0600 Subject: [PATCH 348/370] Update PowerSimulations.jl --- src/PowerSimulations.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 43e2aa2ff4..c582b790c9 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -522,7 +522,6 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") -include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") # Services Models From 1ebb9a7096ed67ebe74cb517a1568bec7115a2e2 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 6 Sep 2023 10:31:10 -0600 Subject: [PATCH 349/370] fix pages --- docs/make.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/make.jl b/docs/make.jl index 997ea23e72..4092e05ee3 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -23,8 +23,7 @@ pages = OrderedDict( "modeler_guide/modeling_faq.md", ], "Model Developer Guide" => Any[ - "Adding Formulations" => "model_developer_guide/adding_new_device_formulation.md" - "Adding Problems" => "model_developer_guide/adding_new_problem_model.md" + "Operation Problem Structure" => "model_developer_guide/structure_of_operation_problem.md" "Troubleshooting" => "model_developer_guide/troubleshooting.md" ], "Code Base Developer Guide" => Any[ From 2113c5538aba63c47269d708cbc415f8cd0fc11a Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 6 Sep 2023 13:06:53 -0600 Subject: [PATCH 350/370] remove hydro references --- src/PowerSimulations.jl | 1 - test/runtests.jl | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 245260d4f7..cb6e30dc00 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -534,7 +534,6 @@ include("initial_conditions/initialization.jl") # Device constructors include("devices_models/device_constructors/constructor_validations.jl") include("devices_models/device_constructors/thermalgeneration_constructor.jl") -include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") diff --git a/test/runtests.jl b/test/runtests.jl index 99ba5b9111..91075c027c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -4,6 +4,7 @@ using PowerSystems using PowerSystemCaseBuilder using InfrastructureSystems using PowerNetworkMatrices +using HydroPowerSimulations import PowerSystemCaseBuilder: PSITestSystems using PowerNetworkMatrices From 3ad18e2667a6455f7c3b08fb9a2c9b657a8937a1 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 6 Sep 2023 13:33:08 -0600 Subject: [PATCH 351/370] some additional changes for hydro --- docs/make.jl | 1 - docs/src/formulation_library/HydroGen.md | 134 ------------------- src/operation/operation_problem_templates.jl | 2 - test/performance/performance_test.jl | 1 + test/test_formulation_combinations.jl | 4 - 5 files changed, 1 insertion(+), 141 deletions(-) delete mode 100644 docs/src/formulation_library/HydroGen.md diff --git a/docs/make.jl b/docs/make.jl index 4092e05ee3..dda574be59 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -33,7 +33,6 @@ pages = OrderedDict( "Formulation Library" => Any[ "General" => "formulation_library/General.md", "Thermal Generation" => "formulation_library/ThermalGen.md", - "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md deleted file mode 100644 index 29704805f8..0000000000 --- a/docs/src/formulation_library/HydroGen.md +++ /dev/null @@ -1,134 +0,0 @@ -# `PowerSystems.HydroGen` Formulations - -Valid `DeviceModel`s for subtypes of `HydroGen` include the following: - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.generate_device_formulation_combinations() -filter!(x -> x["device_type"] <: HydroGen, combos) -combo_table = DataFrame( - "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], - "Device Type" => ["[$(c["device_type"])](https://nrel-siip.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], - "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], - ) -mdtable(combo_table, latex = false) -``` - ---- - -## `HydroDispatchRunOfRiver` - -```@docs -HydroDispatchRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroDispatchRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} -\end{aligned} -``` - ---- - -## `HydroCommitmentRunOfRiver` - -```@docs -HydroCommitmentRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroCommitmentRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` \ No newline at end of file diff --git a/src/operation/operation_problem_templates.jl b/src/operation/operation_problem_templates.jl index fb6a1f9206..800c0cdb1d 100644 --- a/src/operation/operation_problem_templates.jl +++ b/src/operation/operation_problem_templates.jl @@ -8,8 +8,6 @@ function _default_devices_uc() DeviceModel(PSY.ThermalStandard, ThermalBasicUnitCommitment), DeviceModel(PSY.RenewableDispatch, RenewableFullDispatch), DeviceModel(PSY.RenewableFix, FixedOutput), - DeviceModel(PSY.HydroEnergyReservoir, HydroDispatchRunOfRiver), - DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver), DeviceModel(PSY.PowerLoad, StaticPowerLoad), DeviceModel(PSY.InterruptiblePowerLoad, PowerLoadInterruption), DeviceModel(PSY.Line, StaticBranch), diff --git a/test/performance/performance_test.jl b/test/performance/performance_test.jl index b1a034afc4..f7b0145b29 100644 --- a/test/performance/performance_test.jl +++ b/test/performance/performance_test.jl @@ -7,6 +7,7 @@ const PSY = PowerSystems using Logging using PowerSystemCaseBuilder using PowerNetworkMatrices +using HydroPowerSimulations using HiGHS using Dates diff --git a/test/test_formulation_combinations.jl b/test/test_formulation_combinations.jl index eb1e1dbc98..763f19f595 100644 --- a/test/test_formulation_combinations.jl +++ b/test/test_formulation_combinations.jl @@ -10,10 +10,6 @@ item["formulation"] == PSI.ThermalBasicCompactUnitCommitment found_valid_device = true end - if item["device_type"] == PSY.ThermalStandard && - item["formulation"] == PSI.HydroDispatchRunOfRiver - found_invalid_device = true - end end for item in res["service_formulations"] From 16ea36a8df8c431771b4d267b34bb7a97ba0dceb Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 17:04:30 -0600 Subject: [PATCH 352/370] comment out repeated code with HydroPowerSims --- .../device_constructors/hydrogeneration_constructor.jl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index 534038d7f6..dcd8b3296b 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -70,6 +70,7 @@ function construct_device!( return end +#= """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation """ @@ -132,6 +133,7 @@ function construct_device!( return end + function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -178,6 +180,7 @@ function construct_device!( return end +=# """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation @@ -232,6 +235,7 @@ function construct_device!( return end +#= function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -270,6 +274,7 @@ function construct_device!( add_constraint_dual!(container, sys, model) return end +=# """ Construct model for HydroGen with RunOfRiver Commitment Formulation From 922d0d3c1b138a0b668f566b149e5311a6fa9fa6 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 17:11:09 -0600 Subject: [PATCH 353/370] formatter --- .../device_constructors/hydrogeneration_constructor.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index dcd8b3296b..ff2d5c4f59 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -133,7 +133,6 @@ function construct_device!( return end - function construct_device!( container::OptimizationContainer, sys::PSY.System, From 2d333925d308a971121374b64d5e1b335ceabf97 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 13 Jul 2023 10:47:27 -0600 Subject: [PATCH 354/370] fix hydro tests and references --- .../device_constructors/hydrogeneration_constructor.jl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index ff2d5c4f59..dd43264c65 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -70,7 +70,6 @@ function construct_device!( return end -#= """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation """ @@ -179,7 +178,6 @@ function construct_device!( return end -=# """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation @@ -234,7 +232,7 @@ function construct_device!( return end -#= + function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -273,7 +271,7 @@ function construct_device!( add_constraint_dual!(container, sys, model) return end -=# + """ Construct model for HydroGen with RunOfRiver Commitment Formulation From 3d4d413cd561f9c4863188fab79aebd34526fb09 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 13 Jul 2023 10:50:41 -0600 Subject: [PATCH 355/370] formatter --- .../device_constructors/hydrogeneration_constructor.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index dd43264c65..534038d7f6 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -232,7 +232,6 @@ function construct_device!( return end - function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -272,7 +271,6 @@ function construct_device!( return end - """ Construct model for HydroGen with RunOfRiver Commitment Formulation """ From 4bea30d9e99d13890e408c3737b65d98122259ae Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 17:04:30 -0600 Subject: [PATCH 356/370] comment out repeated code with HydroPowerSims --- .../device_constructors/hydrogeneration_constructor.jl | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index 534038d7f6..dcd8b3296b 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -70,6 +70,7 @@ function construct_device!( return end +#= """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation """ @@ -132,6 +133,7 @@ function construct_device!( return end + function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -178,6 +180,7 @@ function construct_device!( return end +=# """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation @@ -232,6 +235,7 @@ function construct_device!( return end +#= function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -270,6 +274,7 @@ function construct_device!( add_constraint_dual!(container, sys, model) return end +=# """ Construct model for HydroGen with RunOfRiver Commitment Formulation From df4bd613d0996d6b1b3b66daa0cc2603f4b76df1 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Tue, 11 Jul 2023 17:11:09 -0600 Subject: [PATCH 357/370] formatter --- .../device_constructors/hydrogeneration_constructor.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index dcd8b3296b..ff2d5c4f59 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -133,7 +133,6 @@ function construct_device!( return end - function construct_device!( container::OptimizationContainer, sys::PSY.System, From 4cbb931097a567e6059aa6627e158425f1cedba0 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 13 Jul 2023 10:47:27 -0600 Subject: [PATCH 358/370] fix hydro tests and references --- .../device_constructors/hydrogeneration_constructor.jl | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index ff2d5c4f59..dd43264c65 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -70,7 +70,6 @@ function construct_device!( return end -#= """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation """ @@ -179,7 +178,6 @@ function construct_device!( return end -=# """ Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation @@ -234,7 +232,7 @@ function construct_device!( return end -#= + function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -273,7 +271,7 @@ function construct_device!( add_constraint_dual!(container, sys, model) return end -=# + """ Construct model for HydroGen with RunOfRiver Commitment Formulation From 6238aaa7ef73ad5d1984b58651e28342728e5ea0 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Thu, 13 Jul 2023 10:50:41 -0600 Subject: [PATCH 359/370] formatter --- .../device_constructors/hydrogeneration_constructor.jl | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl index dd43264c65..534038d7f6 100644 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ b/src/devices_models/device_constructors/hydrogeneration_constructor.jl @@ -232,7 +232,6 @@ function construct_device!( return end - function construct_device!( container::OptimizationContainer, sys::PSY.System, @@ -272,7 +271,6 @@ function construct_device!( return end - """ Construct model for HydroGen with RunOfRiver Commitment Formulation """ From 6e2c56f775e7688f14ad948b470189ab3bbf6eb0 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 6 Sep 2023 10:31:10 -0600 Subject: [PATCH 360/370] fix pages --- docs/make.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/make.jl b/docs/make.jl index 997ea23e72..4092e05ee3 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -23,8 +23,7 @@ pages = OrderedDict( "modeler_guide/modeling_faq.md", ], "Model Developer Guide" => Any[ - "Adding Formulations" => "model_developer_guide/adding_new_device_formulation.md" - "Adding Problems" => "model_developer_guide/adding_new_problem_model.md" + "Operation Problem Structure" => "model_developer_guide/structure_of_operation_problem.md" "Troubleshooting" => "model_developer_guide/troubleshooting.md" ], "Code Base Developer Guide" => Any[ From 04330574c4885997ce6cf9582e122d87b607d751 Mon Sep 17 00:00:00 2001 From: pesap Date: Thu, 24 Aug 2023 17:26:34 -0600 Subject: [PATCH 361/370] Removing Hydro related stuff. --- src/PowerSimulations.jl | 2 +- src/core/formulations.jl | 26 ++-- ...st_device_hydro_generation_constructors.jl | 121 ------------------ 3 files changed, 14 insertions(+), 135 deletions(-) delete mode 100644 test/test_device_hydro_generation_constructors.jl diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index d142923b95..9433dd958b 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -70,7 +70,7 @@ export DeviceLimitedRegulation export ReserveLimitedRegulation ###### Hydro ####### -export HydroDispatchRunOfRiver +# export HydroDispatchRunOfRiver export HydroCommitmentRunOfRiver # feedforward models diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 6752ad5599..4fefb8d6f1 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -73,19 +73,19 @@ Formulation type to enable (continuous) load interruption dispatch struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end ############################ Hydro Generation Formulations ################################# -abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end -abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end -abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end - -""" -Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` -""" -struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end - -""" -Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` -""" -struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end +# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end +# abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end +# abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end + +# """ +# Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` +# """ +# struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end + +# """ +# Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` +# """ +# struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end diff --git a/test/test_device_hydro_generation_constructors.jl b/test/test_device_hydro_generation_constructors.jl deleted file mode 100644 index 7545c57ace..0000000000 --- a/test/test_device_hydro_generation_constructors.jl +++ /dev/null @@ -1,121 +0,0 @@ -################################### -###### FIXED OUTPUT TESTS ######### -################################### - -@testset "Hydro DCPLossLess FixedOutput" begin - device_model = DeviceModel(HydroDispatch, FixedOutput) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with FixedOutput formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, FixedOutput) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 0, 0, 0, 0, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -### RUN OF RIVER DISPATCH TESTS ### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroDispatchRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 24, 0, 48, 24, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroDispatchRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroDispatchRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 72, 48, 0, false) - psi_checkobjfun_test(model, GAEVF) -end - -################################### -#### RUN OF RIVER COMMIT TESTS #### -################################### - -@testset "Hydro DCPLossLess HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroDispatch with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroDispatch, HydroCommitmentRunOfRiver) - c_sys5_hy = PSB.build_system(PSITestSystems, "c_sys5_hy") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hy) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro DCPLossLess HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, DCPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 48, 0, 48, 24, 0, true) - psi_checkobjfun_test(model, GAEVF) -end - -@testset "Hydro ACPPowerModel HydroEnergyReservoir with HydroCommitmentRunOfRiver formulations" begin - device_model = DeviceModel(HydroEnergyReservoir, HydroCommitmentRunOfRiver) - c_sys5_hyd = PSB.build_system(PSITestSystems, "c_sys5_hyd") - - # No Parameters Testing - model = DecisionModel(MockOperationProblem, ACPPowerModel, c_sys5_hyd) - mock_construct_device!(model, device_model) - moi_tests(model, 72, 0, 72, 48, 0, true) - psi_checkobjfun_test(model, GAEVF) -end From f77beea6d81024bf01eb8f8286741fdb5ef61727 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 6 Sep 2023 10:20:31 -0600 Subject: [PATCH 362/370] Update PowerSimulations.jl --- src/PowerSimulations.jl | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 9433dd958b..97a30e518c 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -69,10 +69,6 @@ export ThermalCompactDispatch export DeviceLimitedRegulation export ReserveLimitedRegulation -###### Hydro ####### -# export HydroDispatchRunOfRiver -export HydroCommitmentRunOfRiver - # feedforward models export UpperBoundFeedforward export LowerBoundFeedforward From da22a6569b18a3ed6c3360a5ab98c4841a6bf8ac Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 6 Sep 2023 10:21:13 -0600 Subject: [PATCH 363/370] Update formulations.jl --- src/core/formulations.jl | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/core/formulations.jl b/src/core/formulations.jl index 4fefb8d6f1..73e801cdf6 100644 --- a/src/core/formulations.jl +++ b/src/core/formulations.jl @@ -72,21 +72,6 @@ Formulation type to enable (continuous) load interruption dispatch """ struct PowerLoadDispatch <: AbstractControllablePowerLoadFormulation end -############################ Hydro Generation Formulations ################################# -# abstract type AbstractHydroFormulation <: AbstractDeviceFormulation end -# abstract type AbstractHydroDispatchFormulation <: AbstractHydroFormulation end -# abstract type AbstractHydroUnitCommitment <: AbstractHydroFormulation end - -# """ -# Formulation type to add injection variables constrained by a maximum injection time series for `HydroGen` -# """ -# struct HydroDispatchRunOfRiver <: AbstractHydroDispatchFormulation end - -# """ -# Formulation type to add commitment and injection variables constrained by a maximum injection time series for `HydroGen` -# """ -# struct HydroCommitmentRunOfRiver <: AbstractHydroUnitCommitment end - ############################ Regulation Device Formulations ################################ abstract type AbstractRegulationFormulation <: AbstractDeviceFormulation end struct ReserveLimitedRegulation <: AbstractRegulationFormulation end From 1a7c78e5daed0c5ef532938e612bc9e7a6a8e01c Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 6 Sep 2023 10:21:33 -0600 Subject: [PATCH 364/370] Delete src/devices_models/device_constructors/hydrogeneration_constructor.jl --- .../hydrogeneration_constructor.jl | 468 ------------------ 1 file changed, 468 deletions(-) delete mode 100644 src/devices_models/device_constructors/hydrogeneration_constructor.jl diff --git a/src/devices_models/device_constructors/hydrogeneration_constructor.jl b/src/devices_models/device_constructors/hydrogeneration_constructor.jl deleted file mode 100644 index 534038d7f6..0000000000 --- a/src/devices_models/device_constructors/hydrogeneration_constructor.jl +++ /dev/null @@ -1,468 +0,0 @@ -""" -Construct model for HydroGen with FixedOutput Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_parameters!(container, ReactivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -function construct_device!( - ::OptimizationContainer, - ::PSY.System, - ::ModelConstructStage, - ::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractPowerModel} - # FixedOutput doesn't add any constraints to the model. This function covers - # AbstractPowerModel and AbstractActivePowerModel - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, FixedOutput}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, S <: PM.AbstractActivePowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - # Expression - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerTimeSeriesParameter, - devices, - model, - network_model, - ) - return -end - -""" -Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: Union{HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: Union{HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}, - S <: PM.AbstractPowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - add_constraint_dual!(container, sys, model) - - return -end - -""" -Construct model for HydroGen with RunOfRiver (default Hydro model) Dispatch Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroDispatchRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroDispatchRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, ReactivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_to_expression!( - container, - ReactivePowerBalance, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where {H <: PSY.HydroGen, D <: HydroCommitmentRunOfRiver, S <: PM.AbstractPowerModel} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_constraints!( - container, - ReactivePowerVariableLimitsConstraint, - ReactivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end - -""" -Construct model for HydroGen with RunOfRiver Commitment Formulation -with only Active Power. -""" -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ArgumentConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_variables!(container, ActivePowerVariable, devices, D()) - add_variables!(container, OnVariable, devices, D()) - add_variables!(container, EnergyOutput, devices, D()) - add_to_expression!( - container, - ActivePowerBalance, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_expressions!(container, ProductionCostExpression, devices, model) - - add_parameters!(container, ActivePowerTimeSeriesParameter, devices, model) - add_to_expression!( - container, - ActivePowerRangeExpressionLB, - ActivePowerVariable, - devices, - model, - network_model, - ) - add_to_expression!( - container, - ActivePowerRangeExpressionUB, - ActivePowerVariable, - devices, - model, - network_model, - ) - - add_feedforward_arguments!(container, model, devices) - return -end - -function construct_device!( - container::OptimizationContainer, - sys::PSY.System, - ::ModelConstructStage, - model::DeviceModel{H, D}, - network_model::NetworkModel{S}, -) where { - H <: PSY.HydroGen, - D <: HydroCommitmentRunOfRiver, - S <: PM.AbstractActivePowerModel, -} - devices = - get_available_components(H, sys, get_attribute(model, "filter_function")) - - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionLB, - devices, - model, - network_model, - ) - add_constraints!( - container, - ActivePowerVariableLimitsConstraint, - ActivePowerRangeExpressionUB, - devices, - model, - network_model, - ) - - add_feedforward_constraints!(container, model, devices) - - objective_function!(container, devices, model, S) - - add_constraint_dual!(container, sys, model) - return -end From a087cb2719bf832356f2a6615d105da8088bcb97 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 6 Sep 2023 10:21:51 -0600 Subject: [PATCH 365/370] Delete src/devices_models/devices/hydro_generation.jl --- .../devices/hydro_generation.jl | 289 ------------------ 1 file changed, 289 deletions(-) delete mode 100644 src/devices_models/devices/hydro_generation.jl diff --git a/src/devices_models/devices/hydro_generation.jl b/src/devices_models/devices/hydro_generation.jl deleted file mode 100644 index f0399d91f1..0000000000 --- a/src/devices_models/devices/hydro_generation.jl +++ /dev/null @@ -1,289 +0,0 @@ -#! format: off -requires_initialization(::AbstractHydroFormulation) = false -requires_initialization(::AbstractHydroUnitCommitment) = true - -get_variable_multiplier(_, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = 1.0 -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveUp}}) = ActivePowerRangeExpressionUB -get_expression_type_for_reserve(::ActivePowerReserveVariable, ::Type{<:PSY.HydroGen}, ::Type{<:PSY.Reserve{PSY.ReserveDown}}) = ActivePowerRangeExpressionLB - -########################### ActivePowerVariable, HydroGen ################################# -get_variable_binary(::ActivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroUnitCommitment) = 0.0 -get_variable_upper_bound(::ActivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max - -############## ActivePowerVariable, HydroDispatchRunOfRiver #################### -get_variable_lower_bound(::ActivePowerVariable, d::PSY.HydroGen, ::HydroDispatchRunOfRiver) = 0.0 - -############## ReactivePowerVariable, HydroGen #################### -get_variable_binary(::ReactivePowerVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = false -get_variable_warm_start_value(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power(d) -get_variable_lower_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).min -get_variable_upper_bound(::ReactivePowerVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_reactive_power_limits(d).max - -############## OnVariable, HydroGen #################### -get_variable_binary(::OnVariable, ::Type{<:PSY.HydroGen}, ::AbstractHydroFormulation) = true -get_variable_warm_start_value(::OnVariable, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) > 0 ? 1.0 : 0.0 - -########################### Parameter related set functions ################################ -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_max_active_power(d) -get_multiplier_value(::TimeSeriesParameter, d::PSY.HydroGen, ::FixedOutput) = PSY.get_max_active_power(d) - -get_parameter_multiplier(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_initial_parameter_value(::VariableValueParameter, d::PSY.HydroGen, ::AbstractHydroFormulation) = 1.0 -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionUB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).max -get_expression_multiplier(::OnStatusParameter, ::ActivePowerRangeExpressionLB, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power_limits(d).min - -#################### Initial Conditions for models ############### -initial_condition_default(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) -initial_condition_variable(::DeviceStatus, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_active_power(d) -initial_condition_variable(::DevicePower, d::PSY.HydroGen, ::AbstractHydroFormulation) = ActivePowerVariable() -initial_condition_default(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? PSY.get_time_at_status(d) : 0.0 -initial_condition_variable(::InitialTimeDurationOn, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() -initial_condition_default(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = PSY.get_status(d) ? 0.0 : PSY.get_time_at_status(d) -initial_condition_variable(::InitialTimeDurationOff, d::PSY.HydroGen, ::AbstractHydroFormulation) = OnVariable() - -########################Objective Function################################################## -proportional_cost(cost::Nothing, ::PSY.HydroGen, ::ActivePowerVariable, ::AbstractHydroFormulation)=0.0 -proportional_cost(cost::PSY.OperationalCost, ::OnVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_fixed(cost) - -objective_function_multiplier(::ActivePowerVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::ActivePowerOutVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE -objective_function_multiplier(::OnVariable, ::AbstractHydroFormulation)=OBJECTIVE_FUNCTION_POSITIVE - -sos_status(::PSY.HydroGen, ::AbstractHydroFormulation)=SOSStatusVariable.NO_VARIABLE -sos_status(::PSY.HydroGen, ::AbstractHydroUnitCommitment)=SOSStatusVariable.VARIABLE - -variable_cost(::Nothing, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=0.0 -variable_cost(cost::PSY.OperationalCost, ::ActivePowerVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) -variable_cost(cost::PSY.OperationalCost, ::ActivePowerOutVariable, ::PSY.HydroGen, ::AbstractHydroFormulation)=PSY.get_variable(cost) - -#! format: on - -function get_initial_conditions_device_model( - ::OperationModel, - ::DeviceModel{T, <:AbstractHydroFormulation}, -) where {T <: PSY.HydroGen} - return DeviceModel(T, HydroCommitmentRunOfRiver) -end - -function get_default_time_series_names( - ::Type{<:PSY.HydroGen}, - ::Type{<:Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}}, -) - return Dict{Type{<:TimeSeriesParameter}, String}( - ActivePowerTimeSeriesParameter => "max_active_power", - ReactivePowerTimeSeriesParameter => "max_active_power", - ) -end - -function get_default_attributes( - ::Type{T}, - ::Type{D}, -) where { - T <: PSY.HydroGen, - D <: Union{FixedOutput, HydroDispatchRunOfRiver, HydroCommitmentRunOfRiver}, -} - return Dict{String, Any}("reservation" => false) -end - -""" -Time series constraints -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:RangeConstraintLBExpressions}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroDispatchRunOfRiver, X <: PM.AbstractPowerModel} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -""" -Add semicontinuous range constraints for Hydro Unit Commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, <:RangeConstraintLBExpressions}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -function add_constraints!( - container::OptimizationContainer, - T::Type{ActivePowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: HydroCommitmentRunOfRiver, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - add_parameterized_upper_bound_range_constraints( - container, - ActivePowerVariableTimeSeriesLimitsConstraint, - U, - ActivePowerTimeSeriesParameter, - devices, - model, - X, - ) - return -end - -""" -Min and max reactive Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ReactivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_reactive_power_limits(x) -end - -""" -Min and max active Power Variable limits -""" -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{<:AbstractHydroFormulation}, -) - return PSY.get_active_power_limits(x) -end - -function get_min_max_limits( - x::PSY.HydroGen, - ::Type{<:ActivePowerVariableLimitsConstraint}, - ::Type{HydroDispatchRunOfRiver}, -) - return (min = 0.0, max = PSY.get_max_active_power(x)) -end - -""" -Add power variable limits constraints for hydro unit commitment formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where {V <: PSY.HydroGen, W <: AbstractHydroUnitCommitment, X <: PM.AbstractPowerModel} - add_semicontinuous_range_constraints!(container, T, U, devices, model, X) - return -end - -""" -Add power variable limits constraints for hydro dispatch formulation -""" -function add_constraints!( - container::OptimizationContainer, - T::Type{<:PowerVariableLimitsConstraint}, - U::Type{<:Union{VariableType, ExpressionType}}, - devices::IS.FlattenIteratorWrapper{V}, - model::DeviceModel{V, W}, - ::NetworkModel{X}, -) where { - V <: PSY.HydroGen, - W <: AbstractHydroDispatchFormulation, - X <: PM.AbstractPowerModel, -} - if !has_semicontinuous_feedforward(model, U) - add_range_constraints!(container, T, U, devices, model, X) - end - return -end - -##################################### Auxillary Variables ############################ -function _calculate_aux_variable_value!( - container::OptimizationContainer, - ::AuxVarKey{EnergyOutput, T}, - system::PSY.System, - p_variable_results::JuMPVariableArray, -) where {T <: PSY.HydroGen} - devices = axes(p_variable_results, 1) - time_steps = get_time_steps(container) - resolution = get_resolution(container) - fraction_of_hour = Dates.value(Dates.Minute(resolution)) / MINUTES_IN_HOUR - aux_variable_container = get_aux_variable(container, EnergyOutput(), T) - for name in devices, t in time_steps - aux_variable_container[name, t] = - jump_value(p_variable_results[name, t]) * fraction_of_hour - end - - return -end - -function calculate_aux_variable_value!( - container::OptimizationContainer, - aux_key::AuxVarKey{EnergyOutput, T}, - system::PSY.System, -) where {T <: PSY.HydroGen} - p_variable_results = get_variable(container, ActivePowerVariable(), T) - _calculate_aux_variable_value!( - container, - aux_key, - system, - p_variable_results, - ) - return -end - -##################################### Hydro generation cost ############################ -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroUnitCommitment} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - add_proportional_cost!(container, OnVariable(), devices, U()) - return -end - -function objective_function!( - container::OptimizationContainer, - devices::IS.FlattenIteratorWrapper{T}, - ::DeviceModel{T, U}, - ::Type{<:PM.AbstractPowerModel}, -) where {T <: PSY.HydroGen, U <: AbstractHydroDispatchFormulation} - add_variable_cost!(container, ActivePowerVariable(), devices, U()) - return -end From 6f0f9fd4782f1e7c55271a447fc5125692ecc8db Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 6 Sep 2023 10:22:44 -0600 Subject: [PATCH 366/370] Update PowerSimulations.jl --- src/PowerSimulations.jl | 1 - 1 file changed, 1 deletion(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 97a30e518c..245260d4f7 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -512,7 +512,6 @@ include("devices_models/devices/thermal_generation.jl") include("devices_models/devices/electric_loads.jl") include("devices_models/devices/AC_branches.jl") include("devices_models/devices/DC_branches.jl") -include("devices_models/devices/hydro_generation.jl") include("devices_models/devices/regulation_device.jl") # Services Models From 5e04b333e596d2a3f70cb6a429306d1ae38ab838 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 6 Sep 2023 13:06:53 -0600 Subject: [PATCH 367/370] remove hydro references --- src/PowerSimulations.jl | 1 - test/runtests.jl | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PowerSimulations.jl b/src/PowerSimulations.jl index 245260d4f7..cb6e30dc00 100644 --- a/src/PowerSimulations.jl +++ b/src/PowerSimulations.jl @@ -534,7 +534,6 @@ include("initial_conditions/initialization.jl") # Device constructors include("devices_models/device_constructors/constructor_validations.jl") include("devices_models/device_constructors/thermalgeneration_constructor.jl") -include("devices_models/device_constructors/hydrogeneration_constructor.jl") include("devices_models/device_constructors/branch_constructor.jl") include("devices_models/device_constructors/renewablegeneration_constructor.jl") include("devices_models/device_constructors/load_constructor.jl") diff --git a/test/runtests.jl b/test/runtests.jl index 99ba5b9111..91075c027c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -4,6 +4,7 @@ using PowerSystems using PowerSystemCaseBuilder using InfrastructureSystems using PowerNetworkMatrices +using HydroPowerSimulations import PowerSystemCaseBuilder: PSITestSystems using PowerNetworkMatrices From 6e8b87b6a68bfbb1a1064122ddbc7e0900d980cf Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 6 Sep 2023 13:33:08 -0600 Subject: [PATCH 368/370] some additional changes for hydro --- docs/make.jl | 1 - docs/src/formulation_library/HydroGen.md | 134 ------------------- src/operation/operation_problem_templates.jl | 2 - test/performance/performance_test.jl | 1 + test/test_formulation_combinations.jl | 4 - 5 files changed, 1 insertion(+), 141 deletions(-) delete mode 100644 docs/src/formulation_library/HydroGen.md diff --git a/docs/make.jl b/docs/make.jl index 4092e05ee3..dda574be59 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -33,7 +33,6 @@ pages = OrderedDict( "Formulation Library" => Any[ "General" => "formulation_library/General.md", "Thermal Generation" => "formulation_library/ThermalGen.md", - "Hydro Generation" => "formulation_library/HydroGen.md", "Renewable Generation" => "formulation_library/RenewableGen.md", "Load" => "formulation_library/Load.md", "Network" => "formulation_library/Network.md", diff --git a/docs/src/formulation_library/HydroGen.md b/docs/src/formulation_library/HydroGen.md deleted file mode 100644 index 29704805f8..0000000000 --- a/docs/src/formulation_library/HydroGen.md +++ /dev/null @@ -1,134 +0,0 @@ -# `PowerSystems.HydroGen` Formulations - -Valid `DeviceModel`s for subtypes of `HydroGen` include the following: - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.generate_device_formulation_combinations() -filter!(x -> x["device_type"] <: HydroGen, combos) -combo_table = DataFrame( - "Valid DeviceModel" => ["`DeviceModel($(c["device_type"]), $(c["formulation"]))`" for c in combos], - "Device Type" => ["[$(c["device_type"])](https://nrel-siip.github.io/PowerSystems.jl/stable/model_library/generated_$(c["device_type"])/)" for c in combos], - "Formulation" => ["[$(c["formulation"])](@ref)" for c in combos], - ) -mdtable(combo_table, latex = false) -``` - ---- - -## `HydroDispatchRunOfRiver` - -```@docs -HydroDispatchRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroDispatchRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as `` Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ -& Qg^\text{min} \le Qg_t \le Qg^\text{max} -\end{aligned} -``` - ---- - -## `HydroCommitmentRunOfRiver` - -```@docs -HydroCommitmentRunOfRiver -``` - -**Variables:** - -- [`ActivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_active_power(device)` -- [`ReactivePowerVariable`](@ref): - - Bounds: [0.0, ] - - Default initial value: `PowerSystems.get_reactive_power(device)` -- [`OnVariable`](@ref): - - Bounds: {0, 1} - - Default initial value: `PowerSystems.get_status(device)` - -**Static Parameters:** - -- ``Pg^\text{min}`` = `PowerSystems.get_active_power_limits(device).min` -- ``Qg^\text{min}`` = `PowerSystems.get_reactive_power_limits(device).min` -- ``Qg^\text{max}`` = `PowerSystems.get_reactive_power_limits(device).max` - -**Time Series Parameters:** - -```@eval -using PowerSimulations -using PowerSystems -using DataFrames -using Latexify -combos = PowerSimulations.get_default_time_series_names(HydroGen, HydroCommitmentRunOfRiver) -combo_table = DataFrame( - "Parameter" => map(x -> "[`$x`](@ref)", collect(keys(combos))), - "Default Time Series Name" => map(x -> "`$x`", collect(values(combos))), - ) -mdtable(combo_table, latex = false) -``` - -**Objective:** - -Creates an objective function term based on the [`VariableCost` Options](@ref) where the quantity term is defined as ``Pg``. - -**Expressions:** - -Adds ``Pg`` and ``Qg`` terms to the respective active and reactive power balance expressions created by the selected [Network Formulations](@ref) - -**Constraints:** - -```math -\begin{aligned} -& Pg^\text{min} \le Pg_t \le ActivePowerTimeSeriesParameter_t \\ -& Pg_t - u_t Pg^\text{max} \le 0 \\ -& Pg_t - u_t Pg^\text{min} \ge 0 \\ -& Qg_t - u_t Qg^\text{max} \le 0 \\ -& Qg_t - u_t Qg^\text{min} \ge 0 -\end{aligned} -``` \ No newline at end of file diff --git a/src/operation/operation_problem_templates.jl b/src/operation/operation_problem_templates.jl index fb6a1f9206..800c0cdb1d 100644 --- a/src/operation/operation_problem_templates.jl +++ b/src/operation/operation_problem_templates.jl @@ -8,8 +8,6 @@ function _default_devices_uc() DeviceModel(PSY.ThermalStandard, ThermalBasicUnitCommitment), DeviceModel(PSY.RenewableDispatch, RenewableFullDispatch), DeviceModel(PSY.RenewableFix, FixedOutput), - DeviceModel(PSY.HydroEnergyReservoir, HydroDispatchRunOfRiver), - DeviceModel(PSY.HydroDispatch, HydroDispatchRunOfRiver), DeviceModel(PSY.PowerLoad, StaticPowerLoad), DeviceModel(PSY.InterruptiblePowerLoad, PowerLoadInterruption), DeviceModel(PSY.Line, StaticBranch), diff --git a/test/performance/performance_test.jl b/test/performance/performance_test.jl index b1a034afc4..f7b0145b29 100644 --- a/test/performance/performance_test.jl +++ b/test/performance/performance_test.jl @@ -7,6 +7,7 @@ const PSY = PowerSystems using Logging using PowerSystemCaseBuilder using PowerNetworkMatrices +using HydroPowerSimulations using HiGHS using Dates diff --git a/test/test_formulation_combinations.jl b/test/test_formulation_combinations.jl index eb1e1dbc98..763f19f595 100644 --- a/test/test_formulation_combinations.jl +++ b/test/test_formulation_combinations.jl @@ -10,10 +10,6 @@ item["formulation"] == PSI.ThermalBasicCompactUnitCommitment found_valid_device = true end - if item["device_type"] == PSY.ThermalStandard && - item["formulation"] == PSI.HydroDispatchRunOfRiver - found_invalid_device = true - end end for item in res["service_formulations"] From 94c9e4d57a5befa0efb4be6f517353b9206acdaf Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 6 Sep 2023 14:50:27 -0600 Subject: [PATCH 369/370] add missing slack use key --- src/feedforward/feedforward_constraints.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/src/feedforward/feedforward_constraints.jl b/src/feedforward/feedforward_constraints.jl index f7b3b798df..d29f4c79a3 100644 --- a/src/feedforward/feedforward_constraints.jl +++ b/src/feedforward/feedforward_constraints.jl @@ -343,6 +343,7 @@ function add_feedforward_constraints!( meta = "$(var_type)lb", ) + use_slacks = get_slacks(ff) for t in time_steps, name in set_name if use_slacks slack_var = From 33fe60bd7cd97a7dd04d2f565314faecec6ceb74 Mon Sep 17 00:00:00 2001 From: Jose Daniel Lara Date: Wed, 6 Sep 2023 15:18:54 -0600 Subject: [PATCH 370/370] bump version --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index d6ecd2ebe1..122a7c1727 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "PowerSimulations" uuid = "e690365d-45e2-57bb-ac84-44ba829e73c4" authors = ["Jose Daniel Lara", "Clayton Barrows", "Daniel Thom", "Dheepak Krishnamurthy", "Sourabh Dalvi"] -version = "0.21.4" +version = "0.22.0" [deps] CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"