diff --git a/src/descriptors/power_system_structs.json b/src/descriptors/power_system_structs.json index 7119b03431..5898a93d97 100644 --- a/src/descriptors/power_system_structs.json +++ b/src/descriptors/power_system_structs.json @@ -4030,7 +4030,7 @@ }, { "struct_name": "EnergyReservoirStorage", - "docstring": "An energy storage device, modeled as a generic energy reservoir.\n\nThis is suitable for modeling storage charging and discharging with a round-trip efficiency, ignoring the physical dynamics of the storage unit. A variety of energy storage types and chemistries can be modeled with this approach", + "docstring": "An energy storage device, modeled as a generic energy reservoir.\n\nThis is suitable for modeling storage charging and discharging with average efficiency losses, ignoring the physical dynamics of the storage unit. A variety of energy storage types and chemistries can be modeled with this approach", "fields": [ { "null_value": "init", @@ -4064,9 +4064,9 @@ "data_type": "StorageTech" }, { - "name": "initial_energy", + "name": "storage_capacity", + "comment": "Maximum storage capacity (can be in units of, e.g., MWh for batteries or liters for hydrogen)", "null_value": "0.0", - "comment": "State of Charge of the Battery p.u.-hr", "data_type": "Float64", "valid_range": { "min": 0, @@ -4076,13 +4076,24 @@ "needs_conversion": true }, { - "name": "state_of_charge_limits", + "name": "storage_level_limits", "null_value": "(min=0.0, max=0.0)", - "comment": "Maximum and Minimum storage capacity in p.u.-hr", + "comment": "Minimum and maximum allowable storage levels [0, 1], which can be used to model derates or other restrictions, such as state-of-charge restrictions on battery cycling", "data_type": "MinMax", "valid_range": { "min": 0, - "max": null + "max": 1 + }, + "validation_action": "error" + }, + { + "name": "initial_storage_capacity_level", + "null_value": "0.0", + "comment": "Initial storage capacity level as a ratio [0, 1.0] of `storage_capacity`", + "data_type": "Float64", + "valid_range": { + "min": 0, + "max": 1 }, "validation_action": "error", "needs_conversion": true @@ -4103,6 +4114,7 @@ }, { "name": "input_active_power_limits", + "comment": "Minimum and maximum limits on the input active power (i.e., charging)", "null_value": "(min=0.0, max=0.0)", "data_type": "MinMax", "valid_range": { @@ -4114,6 +4126,7 @@ }, { "name": "output_active_power_limits", + "comment": "Minimum and maximum limits on the output active power (i.e., discharging)", "null_value": "(min=0.0, max=0.0)", "data_type": "MinMax", "valid_range": { @@ -4125,6 +4138,7 @@ }, { "name": "efficiency", + "comment": "Average efficiency [0, 1] `in` (charging/filling) and `out` (discharging/consuming) of the storage system", "null_value": "(in=0.0, out=0.0)", "data_type": "NamedTuple{(:in, :out), Tuple{Float64, Float64}}", "valid_range": { @@ -4160,6 +4174,13 @@ }, "validation_action": "warn" }, + { + "name": "conversion_factor", + "comment": "Conversion factor of `storage_capacity` to MWh, if different than 1.0. For example, X MWh/liter hydrogen", + "null_value": "0.0", + "data_type": "Float64", + "default": "1.0" + }, { "name": "operation_cost", "comment": "[Operating cost](@ref cost_library) of storage", diff --git a/src/models/generated/EnergyReservoirStorage.jl b/src/models/generated/EnergyReservoirStorage.jl index 92e27fc91c..378385f935 100644 --- a/src/models/generated/EnergyReservoirStorage.jl +++ b/src/models/generated/EnergyReservoirStorage.jl @@ -11,8 +11,9 @@ This file is auto-generated. Do not edit. bus::ACBus prime_mover_type::PrimeMovers storage_technology_type::StorageTech - initial_energy::Float64 - state_of_charge_limits::MinMax + storage_capacity::Float64 + storage_level_limits::MinMax + initial_storage_capacity_level::Float64 rating::Float64 active_power::Float64 input_active_power_limits::MinMax @@ -21,6 +22,7 @@ This file is auto-generated. Do not edit. reactive_power::Float64 reactive_power_limits::Union{Nothing, MinMax} base_power::Float64 + conversion_factor::Float64 operation_cost::StorageCost storage_target::Float64 cycle_limits::Int @@ -32,7 +34,7 @@ This file is auto-generated. Do not edit. An energy storage device, modeled as a generic energy reservoir. -This is suitable for modeling storage charging and discharging with a round-trip efficiency, ignoring the physical dynamics of the storage unit. A variety of energy storage types and chemistries can be modeled with this approach +This is suitable for modeling storage charging and discharging with average efficiency losses, ignoring the physical dynamics of the storage unit. A variety of energy storage types and chemistries can be modeled with this approach # Arguments - `name::String`: Name of the component. Components of the same type (e.g., `PowerLoad`) must have unique names, but components of different types (e.g., `PowerLoad` and `ACBus`) can have the same name @@ -40,16 +42,18 @@ This is suitable for modeling storage charging and discharging with a round-trip - `bus::ACBus`: Bus that this component is connected to - `prime_mover_type::PrimeMovers`: Prime mover technology according to EIA 923. Options are listed [here](@ref pm_list) - `storage_technology_type::StorageTech`: Storage Technology Complementary to EIA 923 -- `initial_energy::Float64`: State of Charge of the Battery p.u.-hr, validation range: `(0, nothing)` -- `state_of_charge_limits::MinMax`: Maximum and Minimum storage capacity in p.u.-hr, validation range: `(0, nothing)` +- `storage_capacity::Float64`: Maximum storage capacity (can be in units of, e.g., MWh for batteries or liters for hydrogen), validation range: `(0, nothing)` +- `storage_level_limits::MinMax`: Minimum and maximum allowable storage levels [0, 1], which can be used to model derates or other restrictions, such as state-of-charge restrictions on battery cycling, validation range: `(0, 1)` +- `initial_storage_capacity_level::Float64`: Initial storage capacity level as a ratio [0, 1.0] of `storage_capacity`, validation range: `(0, 1)` - `rating::Float64`: Maximum output power rating of the unit (MVA) - `active_power::Float64`: Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used -- `input_active_power_limits::MinMax`:, validation range: `(0, nothing)` -- `output_active_power_limits::MinMax`:, validation range: `(0, nothing)` -- `efficiency::NamedTuple{(:in, :out), Tuple{Float64, Float64}}`:, validation range: `(0, 1)` +- `input_active_power_limits::MinMax`: Minimum and maximum limits on the input active power (i.e., charging), validation range: `(0, nothing)` +- `output_active_power_limits::MinMax`: Minimum and maximum limits on the output active power (i.e., discharging), validation range: `(0, nothing)` +- `efficiency::NamedTuple{(:in, :out), Tuple{Float64, Float64}}`: Average efficiency [0, 1] `in` (charging/filling) and `out` (discharging/consuming) of the storage system, validation range: `(0, 1)` - `reactive_power::Float64`: Initial reactive power set point of the unit (MVAR), validation range: `reactive_power_limits` - `reactive_power_limits::Union{Nothing, MinMax}`: Minimum and maximum reactive power limits. Set to `Nothing` if not applicable - `base_power::Float64`: Base power of the unit (MVA) for per unitization, which is commonly the same as `rating`, validation range: `(0, nothing)` +- `conversion_factor::Float64`: (default: `1.0`) Conversion factor of `storage_capacity` to MWh, if different than 1.0. For example, X MWh/liter hydrogen - `operation_cost::StorageCost`: (default: `StorageCost(nothing)`) [Operating cost](@ref cost_library) of storage - `storage_target::Float64`: (default: `0.0`) Storage target at the end of simulation as ratio of storage capacity - `cycle_limits::Int`: (default: `1e4`) Storage Maximum number of cycles per year @@ -69,16 +73,21 @@ mutable struct EnergyReservoirStorage <: Storage prime_mover_type::PrimeMovers "Storage Technology Complementary to EIA 923" storage_technology_type::StorageTech - "State of Charge of the Battery p.u.-hr" - initial_energy::Float64 - "Maximum and Minimum storage capacity in p.u.-hr" - state_of_charge_limits::MinMax + "Maximum storage capacity (can be in units of, e.g., MWh for batteries or liters for hydrogen)" + storage_capacity::Float64 + "Minimum and maximum allowable storage levels [0, 1], which can be used to model derates or other restrictions, such as state-of-charge restrictions on battery cycling" + storage_level_limits::MinMax + "Initial storage capacity level as a ratio [0, 1.0] of `storage_capacity`" + initial_storage_capacity_level::Float64 "Maximum output power rating of the unit (MVA)" rating::Float64 "Initial active power set point of the unit in MW. For power flow, this is the steady state operating point of the system. For production cost modeling, this may or may not be used as the initial starting point for the solver, depending on the solver used" active_power::Float64 + "Minimum and maximum limits on the input active power (i.e., charging)" input_active_power_limits::MinMax + "Minimum and maximum limits on the output active power (i.e., discharging)" output_active_power_limits::MinMax + "Average efficiency [0, 1] `in` (charging/filling) and `out` (discharging/consuming) of the storage system" efficiency::NamedTuple{(:in, :out), Tuple{Float64, Float64}} "Initial reactive power set point of the unit (MVAR)" reactive_power::Float64 @@ -86,6 +95,8 @@ mutable struct EnergyReservoirStorage <: Storage reactive_power_limits::Union{Nothing, MinMax} "Base power of the unit (MVA) for per unitization, which is commonly the same as `rating`" base_power::Float64 + "Conversion factor of `storage_capacity` to MWh, if different than 1.0. For example, X MWh/liter hydrogen" + conversion_factor::Float64 "[Operating cost](@ref cost_library) of storage" operation_cost::StorageCost "Storage target at the end of simulation as ratio of storage capacity" @@ -102,12 +113,12 @@ mutable struct EnergyReservoirStorage <: Storage internal::InfrastructureSystemsInternal end -function EnergyReservoirStorage(name, available, bus, prime_mover_type, storage_technology_type, initial_energy, state_of_charge_limits, rating, active_power, input_active_power_limits, output_active_power_limits, efficiency, reactive_power, reactive_power_limits, base_power, operation_cost=StorageCost(nothing), storage_target=0.0, cycle_limits=1e4, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), ) - EnergyReservoirStorage(name, available, bus, prime_mover_type, storage_technology_type, initial_energy, state_of_charge_limits, rating, active_power, input_active_power_limits, output_active_power_limits, efficiency, reactive_power, reactive_power_limits, base_power, operation_cost, storage_target, cycle_limits, services, dynamic_injector, ext, InfrastructureSystemsInternal(), ) +function EnergyReservoirStorage(name, available, bus, prime_mover_type, storage_technology_type, storage_capacity, storage_level_limits, initial_storage_capacity_level, rating, active_power, input_active_power_limits, output_active_power_limits, efficiency, reactive_power, reactive_power_limits, base_power, conversion_factor=1.0, operation_cost=StorageCost(nothing), storage_target=0.0, cycle_limits=1e4, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), ) + EnergyReservoirStorage(name, available, bus, prime_mover_type, storage_technology_type, storage_capacity, storage_level_limits, initial_storage_capacity_level, rating, active_power, input_active_power_limits, output_active_power_limits, efficiency, reactive_power, reactive_power_limits, base_power, conversion_factor, operation_cost, storage_target, cycle_limits, services, dynamic_injector, ext, InfrastructureSystemsInternal(), ) end -function EnergyReservoirStorage(; name, available, bus, prime_mover_type, storage_technology_type, initial_energy, state_of_charge_limits, rating, active_power, input_active_power_limits, output_active_power_limits, efficiency, reactive_power, reactive_power_limits, base_power, operation_cost=StorageCost(nothing), storage_target=0.0, cycle_limits=1e4, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), ) - EnergyReservoirStorage(name, available, bus, prime_mover_type, storage_technology_type, initial_energy, state_of_charge_limits, rating, active_power, input_active_power_limits, output_active_power_limits, efficiency, reactive_power, reactive_power_limits, base_power, operation_cost, storage_target, cycle_limits, services, dynamic_injector, ext, internal, ) +function EnergyReservoirStorage(; name, available, bus, prime_mover_type, storage_technology_type, storage_capacity, storage_level_limits, initial_storage_capacity_level, rating, active_power, input_active_power_limits, output_active_power_limits, efficiency, reactive_power, reactive_power_limits, base_power, conversion_factor=1.0, operation_cost=StorageCost(nothing), storage_target=0.0, cycle_limits=1e4, services=Device[], dynamic_injector=nothing, ext=Dict{String, Any}(), internal=InfrastructureSystemsInternal(), ) + EnergyReservoirStorage(name, available, bus, prime_mover_type, storage_technology_type, storage_capacity, storage_level_limits, initial_storage_capacity_level, rating, active_power, input_active_power_limits, output_active_power_limits, efficiency, reactive_power, reactive_power_limits, base_power, conversion_factor, operation_cost, storage_target, cycle_limits, services, dynamic_injector, ext, internal, ) end # Constructor for demo purposes; non-functional. @@ -118,8 +129,9 @@ function EnergyReservoirStorage(::Nothing) bus=ACBus(nothing), prime_mover_type=PrimeMovers.BA, storage_technology_type=StorageTech.OTHER_CHEM, - initial_energy=0.0, - state_of_charge_limits=(min=0.0, max=0.0), + storage_capacity=0.0, + storage_level_limits=(min=0.0, max=0.0), + initial_storage_capacity_level=0.0, rating=0.0, active_power=0.0, input_active_power_limits=(min=0.0, max=0.0), @@ -128,6 +140,7 @@ function EnergyReservoirStorage(::Nothing) reactive_power=0.0, reactive_power_limits=(min=0.0, max=0.0), base_power=0.0, + conversion_factor=0.0, operation_cost=StorageCost(nothing), storage_target=0.0, cycle_limits=0, @@ -147,10 +160,12 @@ get_bus(value::EnergyReservoirStorage) = value.bus get_prime_mover_type(value::EnergyReservoirStorage) = value.prime_mover_type """Get [`EnergyReservoirStorage`](@ref) `storage_technology_type`.""" get_storage_technology_type(value::EnergyReservoirStorage) = value.storage_technology_type -"""Get [`EnergyReservoirStorage`](@ref) `initial_energy`.""" -get_initial_energy(value::EnergyReservoirStorage) = get_value(value, value.initial_energy) -"""Get [`EnergyReservoirStorage`](@ref) `state_of_charge_limits`.""" -get_state_of_charge_limits(value::EnergyReservoirStorage) = get_value(value, value.state_of_charge_limits) +"""Get [`EnergyReservoirStorage`](@ref) `storage_capacity`.""" +get_storage_capacity(value::EnergyReservoirStorage) = get_value(value, value.storage_capacity) +"""Get [`EnergyReservoirStorage`](@ref) `storage_level_limits`.""" +get_storage_level_limits(value::EnergyReservoirStorage) = value.storage_level_limits +"""Get [`EnergyReservoirStorage`](@ref) `initial_storage_capacity_level`.""" +get_initial_storage_capacity_level(value::EnergyReservoirStorage) = get_value(value, value.initial_storage_capacity_level) """Get [`EnergyReservoirStorage`](@ref) `rating`.""" get_rating(value::EnergyReservoirStorage) = get_value(value, value.rating) """Get [`EnergyReservoirStorage`](@ref) `active_power`.""" @@ -167,6 +182,8 @@ get_reactive_power(value::EnergyReservoirStorage) = get_value(value, value.react get_reactive_power_limits(value::EnergyReservoirStorage) = get_value(value, value.reactive_power_limits) """Get [`EnergyReservoirStorage`](@ref) `base_power`.""" get_base_power(value::EnergyReservoirStorage) = value.base_power +"""Get [`EnergyReservoirStorage`](@ref) `conversion_factor`.""" +get_conversion_factor(value::EnergyReservoirStorage) = value.conversion_factor """Get [`EnergyReservoirStorage`](@ref) `operation_cost`.""" get_operation_cost(value::EnergyReservoirStorage) = value.operation_cost """Get [`EnergyReservoirStorage`](@ref) `storage_target`.""" @@ -190,10 +207,12 @@ set_bus!(value::EnergyReservoirStorage, val) = value.bus = val set_prime_mover_type!(value::EnergyReservoirStorage, val) = value.prime_mover_type = val """Set [`EnergyReservoirStorage`](@ref) `storage_technology_type`.""" set_storage_technology_type!(value::EnergyReservoirStorage, val) = value.storage_technology_type = val -"""Set [`EnergyReservoirStorage`](@ref) `initial_energy`.""" -set_initial_energy!(value::EnergyReservoirStorage, val) = value.initial_energy = set_value(value, val) -"""Set [`EnergyReservoirStorage`](@ref) `state_of_charge_limits`.""" -set_state_of_charge_limits!(value::EnergyReservoirStorage, val) = value.state_of_charge_limits = set_value(value, val) +"""Set [`EnergyReservoirStorage`](@ref) `storage_capacity`.""" +set_storage_capacity!(value::EnergyReservoirStorage, val) = value.storage_capacity = set_value(value, val) +"""Set [`EnergyReservoirStorage`](@ref) `storage_level_limits`.""" +set_storage_level_limits!(value::EnergyReservoirStorage, val) = value.storage_level_limits = val +"""Set [`EnergyReservoirStorage`](@ref) `initial_storage_capacity_level`.""" +set_initial_storage_capacity_level!(value::EnergyReservoirStorage, val) = value.initial_storage_capacity_level = set_value(value, val) """Set [`EnergyReservoirStorage`](@ref) `rating`.""" set_rating!(value::EnergyReservoirStorage, val) = value.rating = set_value(value, val) """Set [`EnergyReservoirStorage`](@ref) `active_power`.""" @@ -210,6 +229,8 @@ set_reactive_power!(value::EnergyReservoirStorage, val) = value.reactive_power = set_reactive_power_limits!(value::EnergyReservoirStorage, val) = value.reactive_power_limits = set_value(value, val) """Set [`EnergyReservoirStorage`](@ref) `base_power`.""" set_base_power!(value::EnergyReservoirStorage, val) = value.base_power = val +"""Set [`EnergyReservoirStorage`](@ref) `conversion_factor`.""" +set_conversion_factor!(value::EnergyReservoirStorage, val) = value.conversion_factor = val """Set [`EnergyReservoirStorage`](@ref) `operation_cost`.""" set_operation_cost!(value::EnergyReservoirStorage, val) = value.operation_cost = val """Set [`EnergyReservoirStorage`](@ref) `storage_target`.""" diff --git a/src/models/generated/includes.jl b/src/models/generated/includes.jl index 17fbfca546..94f87fa788 100644 --- a/src/models/generated/includes.jl +++ b/src/models/generated/includes.jl @@ -497,8 +497,8 @@ export get_impedance_active_power export get_impedance_reactive_power export get_inflow export get_initial_ace -export get_initial_energy export get_initial_storage +export get_initial_storage_capacity_level export get_input_active_power_limits export get_input_code export get_input_code_1 @@ -601,11 +601,11 @@ export get_services export get_speed_error_signal export get_start_time_limits export get_start_types -export get_state_of_charge_limits export get_states export get_states_types export get_status export get_storage_capacity +export get_storage_level_limits export get_storage_target export get_storage_technology_type export get_sustained_time @@ -1026,8 +1026,8 @@ export set_impedance_active_power! export set_impedance_reactive_power! export set_inflow! export set_initial_ace! -export set_initial_energy! export set_initial_storage! +export set_initial_storage_capacity_level! export set_input_active_power_limits! export set_input_code! export set_input_code_1! @@ -1130,11 +1130,11 @@ export set_services! export set_speed_error_signal! export set_start_time_limits! export set_start_types! -export set_state_of_charge_limits! export set_states! export set_states_types! export set_status! export set_storage_capacity! +export set_storage_level_limits! export set_storage_target! export set_storage_technology_type! export set_sustained_time!