-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: Define AncillaryServices types to support different sets of ancillary services #33
Conversation
@@ -2,6 +2,9 @@ const MARKET_WIDE_ZONE = -9999 | |||
const BidName = InlineString31 | |||
const ZoneNum = Int64 | |||
|
|||
|
|||
abstract type SystemRequirements end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Different sets of ancillary services have different sets of requirements associated with them. So this needs to become a type hierarchy too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the requirements and ancillary services are linked across multiple fields, would it be better to develop the new market as a separate subtype of System to avoid major breaking changes to the package?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm debating the pros and cons of that. Having a separate System subtype would keep us free from major breaking changes while developing the second market. On the other hand it's probably good for us to think about common parts of the API from the start, because it'll save us time and energy later when we come to reconcile the two.
off_supplemental_offers::KeyedArray{Union{Missing, Float64}, 2} | ||
end | ||
|
||
struct FiveServices <: AncillaryServices |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FourServices
and FiveServices
are placeholder names. We can think of something more descriptive.
loads::KeyedArray{Float64, 2} | ||
fixed_loads::KeyedArray{Float64, 2} | ||
|
||
load_services::Union{Missing, LoadTimeSeries} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another addition we'll have to think about. One market has fixed_loads
and no load services, the other has no fixed loads and does have load services which submit ancillary service bids.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we likely to get into a situation where we need both? Should we unify them into one field or are the use cases too different?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe we won't need both in the new market, they don't have any fixed loads. I am hesitant to unify them though, just because I think they are quite different concepts. I'll need input from Power Systems to be sure on that.
@@ -30,3 +30,13 @@ function get_bids(system::SystemDA, type_of_bid::Symbol) | |||
return getproperty(system, type_of_bid) | |||
end | |||
end | |||
|
|||
@deprecate get_regulation_offers(system::System) get_regulation_offers(get_ancillary_services(system)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might not want to bother deprecating. I'm not sure it would work well given the name of the function has stayed the same but it acts on a different type in the new design.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deprecating based on types works just fine. I wouldn't worry too much about getters during an RFC PR though since things might change drastically
@@ -236,6 +249,39 @@ end | |||
|
|||
###### Time Series types ###### | |||
|
|||
abstract type AncillaryServices end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As opposed to creating different AncillaryServices types, it might be better to use a more flexible structure. Something like a Dict would allow us to account for markets with any number of services. We could key it with a with a suitable enum or group of singleton types if we needed to limit the possible keys and switch to a more flexible get_offers(::System, ::Service)
getter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, my concern with a Dict/Dictionary
was that the keys would be too unrestricted but using enums or singletons would get around that. I think having the keys defined like that would help a lot with the readability and reliability of the formulation implementation too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update: After a chat with our researchers, it seems like we might not need to worry about a separate set of services once we generalize names/practices across markets.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update to the update: after further research these are indeed subject to change so probably the Dict
solution is the safer way to go.
loads::KeyedArray{Float64, 2} | ||
fixed_loads::KeyedArray{Float64, 2} | ||
|
||
load_services::Union{Missing, LoadTimeSeries} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we likely to get into a situation where we need both? Should we unify them into one field or are the use cases too different?
@@ -22,7 +25,17 @@ Base.@kwdef struct Zone | |||
"Zonal good utility practice requirement (regulation + spinning) (pu)" | |||
good_utility::Float64 | |||
end | |||
const Zones = Dictionary{ZoneNum, Zone} | |||
|
|||
struct ZonalRequirements <: SystemRequirements |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This split seems off to me. It seems like we might want to view the new market as a single-zone market and either split the set of service requirements into separate types or put them in a more variable structure.
We can still split out Zonal and SystemWide into types, it just feels like we're combining layout and service requirements. We also already have zones
in our generators so assuming everything is one big zone could cut down on some workarounds there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good point. I see how this mixes two different concepts. I think changing it so the new market can be treated as a single zone makes sense. We can ditch the different layout concept for now.
@@ -2,6 +2,9 @@ const MARKET_WIDE_ZONE = -9999 | |||
const BidName = InlineString31 | |||
const ZoneNum = Int64 | |||
|
|||
|
|||
abstract type SystemRequirements end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the requirements and ancillary services are linked across multiple fields, would it be better to develop the new market as a separate subtype of System to avoid major breaking changes to the package?
@@ -30,3 +30,13 @@ function get_bids(system::SystemDA, type_of_bid::Symbol) | |||
return getproperty(system, type_of_bid) | |||
end | |||
end | |||
|
|||
@deprecate get_regulation_offers(system::System) get_regulation_offers(get_ancillary_services(system)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deprecating based on types works just fine. I wouldn't worry too much about getters during an RFC PR though since things might change drastically
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not particularly a fan of this approach because it seems too rigid. With this we'd have a services type for MISO and one for ERCOT, and we'll probably have one for ISO X once we implement it too, etc. Not to mention, names such as SystemWideRequirements
make it seem that we're dealing with a general thing, but it is very much ISO-specific. For example, after these changes Zone
still contains regulation
, operating_reserve
, good_utility
which is MISO-specific.
I wonder, why not have it flexible by allowing custom service names to be input? This way we can have the user define what services are there and what are their requirements. For example, let the requirements be defined as a collection (Dict, Array, w/e) of :my_reserve => [(Zone1, 5.0), (Zone2, 10.0), (Zone3, 0.0), (SystemWide, 20.0)]
(the data structure doesn't matter here).
Different markets have different sets of ancillary services and related ancillary service requirements.
Let's assume we want one
SystemDA
type to support multiple markets. The proposal here is to define a type hierarchy for ancillary services that allows us to represent the different ancillary service markets. But this causes a potential difficulty with the accessor functions, because instances ofSystem
with different types ofAncillaryServices
won't have certain ancillary service fields.The solution to that issue is to have a single accessor for the user to get the ancillary services from the
System
. Then eachAncillaryServices
subtype has its own set of accessors.Example: accessing the regulation offers