Skip to content

Commit e5cf0c9

Browse files
authored
Merge branch 'main' into bugfix/check_empty_not_nothing
2 parents 0a75d2d + 54e11af commit e5cf0c9

15 files changed

+838
-134
lines changed

docs/src/how_to/market_bid_cost.md

Lines changed: 75 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,61 @@ A [`MarketBidCost`](@ref) is an `OperationalCost` data structure that allows the
44
cost model that is very similar to most US electricity market auctions with bids for energy
55
and ancillary services jointly. This page showcases how to create data for this cost function.
66

7-
## Adding Energy bids to MarketBidCost
7+
## Adding a Single Incremental Energy bids to MarketBidCost
88

9-
### Step 1: Constructiong device with MarketBidCost
9+
### Construct directly the MarketBidCost using the `make_market_bid_curve` method.
10+
11+
The `make_market_bid_curve` creates an incremental or decremental offer curve from a vector of `n` power values, a vector of `n-1` marginal costs and single initial input. For example, the following code creates an incremental offer curve:
12+
13+
```@repl market_bid_cost
14+
using PowerSystems, Dates
15+
proposed_offer_curve =
16+
make_market_bid_curve([0.0, 100.0, 105.0, 120.0, 130.0], [25.0, 26.0, 28.0, 30.0], 10.0)
17+
```
18+
19+
Then a device with MarketBidCost can be directly instantiated using:
20+
21+
```@repl market_bid_cost
22+
using PowerSystems, Dates
23+
bus = ACBus(1, "nodeE", "REF", 0, 1.0, (min = 0.9, max = 1.05), 230, nothing, nothing)
24+
25+
generator = ThermalStandard(;
26+
name = "Brighton",
27+
available = true,
28+
status = true,
29+
bus = bus,
30+
active_power = 6.0,
31+
reactive_power = 1.50,
32+
rating = 0.75,
33+
prime_mover_type = PrimeMovers.ST,
34+
fuel = ThermalFuels.COAL,
35+
active_power_limits = (min = 0.0, max = 6.0),
36+
reactive_power_limits = (min = -4.50, max = 4.50),
37+
time_limits = (up = 0.015, down = 0.015),
38+
ramp_limits = (up = 5.0, down = 3.0),
39+
operation_cost = MarketBidCost(;
40+
no_load_cost = 0.0,
41+
start_up = (hot = 0.0, warm = 0.0, cold = 0.0),
42+
shut_down = 0.0,
43+
incremental_offer_curves = proposed_offer_curve,
44+
),
45+
base_power = 100.0,
46+
)
47+
```
48+
49+
Similarly, a decremental offer curve can also be created directly using the same helper method:
50+
51+
```@repl market_bid_cost
52+
using PowerSystems, Dates
53+
decremental_offer =
54+
make_market_bid_curve([0.0, 100.0, 105.0, 120.0, 130.0], [30.0, 28.0, 26.0, 25.0], 50.0)
55+
```
56+
57+
and can be added to a `MarketBidCost` using the field `decremental_offer_curves`.
58+
59+
## Adding Time Series Energy bids to MarketBidCost
60+
61+
### Step 1: Constructing device with MarketBidCost
1062

1163
When using [`MarketBidCost`](@ref), the user can add the cost struct to the device specifying
1264
only certain elements, at this point the actual energy cost bids don't need to be populated/passed.
@@ -43,19 +95,22 @@ generator = ThermalStandard(;
4395
### Step 2: Creating the `TimeSeriesData` for the Market Bid
4496

4597
The user is expected to pass the `TimeSeriesData` that holds the energy bid data which can be
46-
of any type (i.e. `SingleTimeSeries` or `Deterministic`) and data can be `Array{Float64}`,
47-
`Array{Tuple{Float64, Float64}}` or `Array{Array{Tuple{Float64,Float64}}`. If the data is
48-
just floats then the cost in the optimization is seen as a constant variable cost, but if
49-
data is a Tuple or `Array{Tuple}` then the model expects the tuples to be cost & power-point
50-
pairs (cost in $/p.u-hr & power-point in p.u-hr), which is modeled same as TwoPartCost or
51-
ThreePartCost. Code below shows an example of how to build a TimeSeriesData.
98+
of any type (i.e. `SingleTimeSeries` or `Deterministic`) and data must be `PiecewiseStepData`.
99+
This data type is created by specifying a vector of `n` powers, and `n-1` marginal costs.
100+
The data must be specified in natural units, that is power in MW and marginal cost in $/MWh
101+
or it will not be accepted when adding to the system.
102+
Code below shows an example of how to build a Deterministic TimeSeries.
52103

53104
```@repl market_bid_cost
105+
initial_time = Dates.DateTime("2020-01-01")
106+
psd1 = PiecewiseStepData([5.0, 7.33, 9.67, 12.0], [2.901, 5.8272, 8.941])
107+
psd2 = PiecewiseStepData([5.0, 7.33, 9.67, 12.0], [3.001, 6.0072, 9.001])
54108
data =
55109
Dict(
56-
Dates.DateTime("2020-01-01") => [
57-
[(0.0, 0.05), (290.1, 0.0733), (582.72, 0.0967), (894.1, 0.120)],
58-
[(0.0, 0.05), (300.1, 0.0733), (600.72, 0.0967), (900.1, 0.120)]],
110+
initial_time => [
111+
psd1,
112+
psd2,
113+
],
59114
)
60115
time_series_data = Deterministic(;
61116
name = "variable_cost",
@@ -64,20 +119,6 @@ time_series_data = Deterministic(;
64119
)
65120
```
66121

67-
**NOTE:** Due to [limitations in DataStructures.jl](https://github.com/JuliaCollections/DataStructures.jl/issues/239),
68-
in `PowerSystems.jl` when creating Forecasts or TimeSeries for your MarketBidCost, you need
69-
to define your data as in the example or with a very explicit container. Otherwise, it won't
70-
discern the types properly in the constructor and will return `SortedDict{Any,Any,Base.Order.ForwardOrdering}` which causes the constructor in `PowerSystems.jl` to fail. For instance, you need to define
71-
the `Dict` with the data as follows:
72-
73-
```julia
74-
# Very verbose dict definition
75-
data = Dict{DateTime, Array{Array{Tuple{Float64, Float64}, 1}, 1}}()
76-
for t in range(initial_time_sys; step = Hour(1), length = window_count)
77-
data[t] = MY_BID_DATA
78-
end
79-
```
80-
81122
### Step 3a: Adding Energy Bid TimeSeriesData to the device
82123

83124
To add energy market bids time-series to the `MarketBidCost`, use `set_variable_cost!`. The
@@ -86,12 +127,20 @@ arguments for `set_variable_cost!` are:
86127
- `sys::System`: PowerSystem System
87128
- `component::StaticInjection`: Static injection device
88129
- `time_series_data::TimeSeriesData`: TimeSeriesData
130+
- `power_units::UnitSystem`: UnitSystem
131+
132+
Currently, time series data only supports natural units for time series data, i.e. MW for power and $/MWh for marginal costs.
89133

90134
```@repl market_bid_cost
91135
sys = System(100.0, [bus], [generator])
92-
set_variable_cost!(sys, generator, time_series_data)
136+
set_variable_cost!(sys, generator, time_series_data, UnitSystem.NATURAL_ITEMS)
93137
```
94138

139+
**Note:** `set_variable_cost!` add curves to the `incremental_offer_curves` in the MarketBidCost.
140+
Similarly, `set_incremental_variable_cost!` can be used to add curves to the `incremental_offer_curves`.
141+
On the other hand, `set_decremental_variable_cost!` must be used to decremental curves (usually for storage or demand).
142+
The creation of the TimeSeriesData is similar to Step 2, using `PiecewiseStepData`
143+
95144
### Step 3b: Adding Service Bid TimeSeriesData to the device
96145

97146
Similar to adding energy market bids, for adding bids for ancillary services, use

src/PowerSystems.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,14 +380,18 @@ export get_data
380380
export iterate_components
381381
export get_time_series_multiple
382382
export get_variable_cost
383+
export get_incremental_variable_cost, get_decremental_variable_cost
383384
export get_no_load_cost
384385
export get_start_up
385386
export get_shut_down
386387
export get_incremental_offer_curves, set_incremental_offer_curves!
387388
export get_decremental_offer_curves, set_decremental_offer_curves!
389+
export get_incremental_initial_input, set_incremental_initial_input!
390+
export get_decremental_initial_input, set_decremental_initial_input!
388391
export get_ancillary_service_offers, set_ancillary_service_offers!
389392
export get_services_bid
390393
export set_variable_cost!
394+
export set_incremental_variable_cost!, set_decremental_variable_cost!
391395
export set_service_bid!
392396
export iterate_windows
393397
export get_window

src/descriptors/power_system_structs.json

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,9 +1070,10 @@
10701070
},
10711071
{
10721072
"name": "loss",
1073-
"comment": "Linear loss model coefficients, where `l0` = constant loss (MW) and `l1` = linearly proportional loss rate (MW of loss per MW of flow)",
1074-
"null_value": "(l0=0.0, l1=0.0)",
1075-
"data_type": "NamedTuple{(:l0, :l1), Tuple{Float64, Float64}}"
1073+
"comment": "Loss model coefficients. It accepts a linear model with a constant loss (MW) and a proportional loss rate (MW of loss per MW of flow). It also accepts a Piecewise loss, with N segments to specify different proportional losses for different segments.",
1074+
"null_value": "LinearCurve(0.0)",
1075+
"data_type": "Union{LinearCurve, PiecewiseIncrementalCurve}",
1076+
"default": "LinearCurve(0.0)"
10761077
},
10771078
{
10781079
"name": "services",
@@ -2600,6 +2601,20 @@
26002601
},
26012602
"validation_action": "warn"
26022603
},
2604+
{
2605+
"name": "dc_current",
2606+
"comment": "DC current (A) on the converter",
2607+
"null_value": "0.0",
2608+
"data_type": "Float64",
2609+
"default": "0.0"
2610+
},
2611+
{
2612+
"name": "max_dc_current",
2613+
"comment": "Maximum stable dc current limits (A)",
2614+
"null_value": "0.0",
2615+
"data_type": "Float64",
2616+
"default": "1e8"
2617+
},
26032618
{
26042619
"name": "loss_function",
26052620
"comment": "Linear or quadratic loss function with respect to the converter current",

0 commit comments

Comments
 (0)