diff --git a/cspell.json b/cspell.json index 998128c..d98d099 100644 --- a/cspell.json +++ b/cspell.json @@ -44,6 +44,8 @@ ,"Vernova" ,"Vmax" ,"Vmin" + ,"RLR" + ,"GLR" ], "ignoreWords": [ "AMPL" diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 566cbcc..4fda612 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -1,7 +1,7 @@ GEM remote: https://rubygems.org/ specs: - activesupport (7.2.1) + activesupport (7.2.1.1) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.3.1) diff --git a/docs/_data/openapi-split.yaml b/docs/_data/openapi-split.yaml index d8f5408..4740963 100644 --- a/docs/_data/openapi-split.yaml +++ b/docs/_data/openapi-split.yaml @@ -201,11 +201,15 @@ paths: $ref: paths/limits_forecast-snapshot.yaml#/current /limits/forecast-snapshot/{period}: $ref: paths/limits_forecast-snapshot.yaml#/historical + /limits/regional/forecast-snapshot: + $ref: paths/limits_forecast-snapshot.yaml#/regional /rating-proposals/realtime: $ref: paths/rating-proposals_realtime.yaml /limits/realtime-snapshot: - $ref: paths/limits_realtime-snapshot.yaml + $ref: paths/limits_realtime-snapshot.yaml#/global + /limits/regional/realtime-snapshot: + $ref: paths/limits_realtime-snapshot.yaml#/regional /rating-proposals/forecast: $ref: paths/rating-proposals_forecasts.yaml diff --git a/docs/_data/paths/limits_forecast-snapshot.yaml b/docs/_data/paths/limits_forecast-snapshot.yaml index f02a640..d1f2772 100644 --- a/docs/_data/paths/limits_forecast-snapshot.yaml +++ b/docs/_data/paths/limits_forecast-snapshot.yaml @@ -4,7 +4,7 @@ current: summary: Limits Forecast Snapshot tags: - Forecasting - parameters: + parameters: &commonParams - $ref: ../components/parameters/offset-period-start.yaml - $ref: ../components/parameters/period-end.yaml - $ref: ../components/parameters/monitoring-set-filter.yaml @@ -102,3 +102,32 @@ historical: <<: *responses '410': $ref: '../openapi-split.yaml#/components/responses/410-problem' + +regional: + get: + <<: *get + operationId: getRegionalLimitsForecastSnapshot + summary: Regional Limits Forecast Snapshot + parameters: *commonParams + description: | + + Similar to [getLimitsForecastSnapshot](#tag/Forecasting/operation/getLimitsForecastSnapshot), + except that it specifically returns only the latest **regionally** limiting ratings + ([RLRs](https://trolie.energy/concepts#regionally-limiting-rating)) + used by the Transmission Provider. + + This is explicitly designed to be used when reconciling forecasts between Transmission Providers + in order to generate globally limiting ratings ([GLRs](https://trolie.energy/concepts#globally-limiting-rating)) + for general use. See the article on + [RC-to-RC Reconciliation](https://trolie.energy/articles/RC-to-RC-reconciliation.html) for more details. + + Outside of this use case, most users should use + [getLimitsForecastSnapshot](#tag/Forecasting/operation/getLimitsForecastSnapshot) to get globally + limiting ratings. + + Clients SHOULD perform Conditional `GET` using the `If-None-Match` header + and the `ETag` of a previous `GET` response to poll this endpoint. Rate + limiting is done on a per Ratings Provider basis, so requests from + independent clients used by the same provider count against the same quota. + + responses: *responses diff --git a/docs/_data/paths/limits_realtime-snapshot.yaml b/docs/_data/paths/limits_realtime-snapshot.yaml index 0b3bada..cb80e8e 100644 --- a/docs/_data/paths/limits_realtime-snapshot.yaml +++ b/docs/_data/paths/limits_realtime-snapshot.yaml @@ -1,59 +1,92 @@ -get: - operationId: getRealTimeLimits - description: | - - Obtain the System Operating Limits in-use by the Transmission Provider. - - Clients SHOULD perform Conditional `GET` using the `If-None-Match` header - and the `ETag` of a previous `GET` response to poll this endpoint. Rate - limiting is done on a per Ratings Provider basis, so requests from - independent clients used by the same provider count against the same quota. - - summary: Limits Real Time Snapshot - tags: - - Real-Time - parameters: - - $ref: ../components/parameters/monitoring-set-filter.yaml - - $ref: ../components/parameters/facility-filter.yaml - responses: - '200': - description: The System Operating Limits snapshot is returned. - content: - application/vnd.trolie.realtime-limits-snapshot.v1+json: - schema: - $ref: "../components/schemas/array-max-monitored-elements.yaml#/realtime-limits-snapshot" - example: - $ref: '../../example-narratives/examples/realtime-limit-set.json' - application/vnd.trolie.realtime-limits-detailed-snapshot.v1+json: - schema: - $ref: "../components/schemas/array-max-monitored-elements.yaml#/realtime-limits-detailed-snapshot" - example: - $ref: '../../example-narratives/examples/realtime-limit-set-detailed.json' - application/vnd.trolie.realtime-limits-snapshot-slim.v1+json: - schema: - $ref: "../components/schemas/array-max-monitored-elements.yaml#/realtime-limits-snapshot-slim" - example: - $ref: '../../example-narratives/examples/realtime-limit-set-slim.json' - headers: - $ref: '../openapi-split.yaml#/components/responses/204/headers' - '304': - $ref: '../openapi-split.yaml#/components/responses/304' - '400': - $ref: '../openapi-split.yaml#/components/responses/400-problem' - '401': - $ref: '../openapi-split.yaml#/components/responses/401-empty' - '403': - $ref: '../openapi-split.yaml#/components/responses/403-empty' - '404': - $ref: '../openapi-split.yaml#/components/responses/404-empty' - '406': - $ref: '../openapi-split.yaml#/components/responses/406-empty' - '429': - $ref: '../openapi-split.yaml#/components/responses/429-empty' - '500': &unexpected-error-empty - $ref: '../openapi-split.yaml#/components/responses/500-empty' - default: *unexpected-error-empty - - security: - - oauth2-primary-flow: - - read:operating-snapshot +global: + get: + operationId: getRealTimeLimits + description: | + + Obtain the System Operating Limits in-use by the Transmission Provider. + + Clients SHOULD perform Conditional `GET` using the `If-None-Match` header + and the `ETag` of a previous `GET` response to poll this endpoint. Rate + limiting is done on a per Ratings Provider basis, so requests from + independent clients used by the same provider count against the same quota. + + summary: Limits Real Time Snapshot + tags: + - Real-Time + parameters: ¶ms + - $ref: ../components/parameters/monitoring-set-filter.yaml + - $ref: ../components/parameters/facility-filter.yaml + responses: &responses + '200': + description: The System Operating Limits snapshot is returned. + content: + application/vnd.trolie.realtime-limits-snapshot.v1+json: + schema: + $ref: "../components/schemas/array-max-monitored-elements.yaml#/realtime-limits-snapshot" + example: + $ref: '../../example-narratives/examples/realtime-limit-set.json' + application/vnd.trolie.realtime-limits-detailed-snapshot.v1+json: + schema: + $ref: "../components/schemas/array-max-monitored-elements.yaml#/realtime-limits-detailed-snapshot" + example: + $ref: '../../example-narratives/examples/realtime-limit-set-detailed.json' + application/vnd.trolie.realtime-limits-snapshot-slim.v1+json: + schema: + $ref: "../components/schemas/array-max-monitored-elements.yaml#/realtime-limits-snapshot-slim" + example: + $ref: '../../example-narratives/examples/realtime-limit-set-slim.json' + headers: + $ref: '../openapi-split.yaml#/components/responses/204/headers' + '304': + $ref: '../openapi-split.yaml#/components/responses/304' + '400': + $ref: '../openapi-split.yaml#/components/responses/400-problem' + '401': + $ref: '../openapi-split.yaml#/components/responses/401-empty' + '403': + $ref: '../openapi-split.yaml#/components/responses/403-empty' + '404': + $ref: '../openapi-split.yaml#/components/responses/404-empty' + '406': + $ref: '../openapi-split.yaml#/components/responses/406-empty' + '429': + $ref: '../openapi-split.yaml#/components/responses/429-empty' + '500': &unexpected-error-empty + $ref: '../openapi-split.yaml#/components/responses/500-empty' + default: *unexpected-error-empty + + security: &security + - oauth2-primary-flow: + - read:operating-snapshot + +regional: + get: + operationId: getRegionalRealTimeLimits + description: | + + Similar to [getRealTimeLimits](#tag/Real-Time/operation/getRealTimeLimits), + except that it specifically returns only the latest **regionally** limiting ratings + ([RLRs](https://trolie.energy/concepts#regionally-limiting-rating)) + used by the Transmission Provider. + + This is explicitly designed to be used when reconciling real-time ratings between Transmission Providers + in order to generate globally limiting ratings ([GLRs](https://trolie.energy/concepts#globally-limiting-rating)) + for general use. See the article on + [RC-to-RC Reconciliation](https://trolie.energy/articles/RC-to-RC-reconciliation.html) for more details. + + Outside of this use case, most users should use + [getRealTimeLimits](#tag/Real-Time/operation/getRealTimeLimits) to get globally + limiting ratings. + + Clients SHOULD perform Conditional `GET` using the `If-None-Match` header + and the `ETag` of a previous `GET` response to poll this endpoint. Rate + limiting is done on a per Ratings Provider basis, so requests from + independent clients used by the same provider count against the same quota. + + + summary: Regional Limits Real Time Snapshot + tags: + - Real-Time + parameters: *params + responses: *responses + security: *security diff --git a/docs/_includes/mermaid_config.js b/docs/_includes/mermaid_config.js new file mode 100644 index 0000000..42a2871 --- /dev/null +++ b/docs/_includes/mermaid_config.js @@ -0,0 +1 @@ +{ sequence: { showSequenceNumbers: true } } \ No newline at end of file diff --git a/docs/articles/RC-to-RC-reconciliation.md b/docs/articles/RC-to-RC-reconciliation.md new file mode 100644 index 0000000..a35cdab --- /dev/null +++ b/docs/articles/RC-to-RC-reconciliation.md @@ -0,0 +1,152 @@ +--- +title: RC-to-RC Reconciliation +parent: Articles +--- + +# Reconciling AARs on RC-RC Interties + +In TROLIE's simplest usage, rating providers send rating proposals to Transmission Providers +using the workflow described in [Forecast Submittal](../example-narratives/submitting-forecasts.md). + +However, two neighboring Transmission Providers, each running independent clearinghouses, will also +have to share ratings. Each TROLIE server must be able to act as a client to achieve this coordination, +with each reaching out to one another. These Transmission Providers also serve in the NERC role of +Reliability Coordinator (RC), which will be the term used throughout this article. + +This article specifically covers reconciling ratings between two clearinghouses. It builds off of the +[peer-monitoring-sets](./peer-monitoring-sets.md) article and assumes that monitoring sets between peers +have been reconciled. + +This article defines a design pattern recommended as a best practice, as it ultimately must +be implemented within TROLIE servers and is only supported by the TROLIE communications specification +rather than mandated by it. + +# Globally Limiting Ratings at the Seams +For most facilities in a reliability coordinator (RC) footprint, the output of the clearinghouse represents +Globally Limiting Ratings or [GLRs](../concepts.md#globally-limiting-rating) that may be used in +operations. However, most RCs don't exist on electrical islands by themselves. They will have interties +with neighboring RCs. Assuming each RC is running its own clearinghouse, or is otherwise generating its +ratings independently, GLRs for these facilities must be resolved after clearinghouse runs in a separate phase. + +# Reconciling Forecast ClearingHouse Results +In terms of TROLIE mechanics, the initial output of each RC's clearinghouse is considered the +[Regionally Limiting Rating](../concepts.md#regionally-limiting-rating) or RLR. Peer TROLIEs can continuously +poll each other for new RLRs using the +[getRegionalLimitsForecastSnapshot](../spec#tag/Forecasting/operation/getRegionalLimitsForecastSnapshot) +operation. + +After receiving RLRs from all neighbors in addition to generating its own, the TROLIE instance can generate a regular +snapshot that consists of [Globally Limiting Ratings](../concepts.md#globally-limiting-rating) or GLRs, that incorporate +the most conservative RLRs for each facility. Only these GLR snapshots should be visible via +[getLimitsForecastSnapshot](../spec#tag/Forecasting/operation/getLimitsForecastSnapshot), which represents the final +ratings that may be used in key decisions such as markets, look-ahead unit commitment and dispatch, and outage +coordination. + +Consider the following sequence for a particular forecast interval. Note that certain events can easily occur out of order, +as each neighbor's system will be making the same forecast decisions at slightly different times: + +```mermaid +sequenceDiagram + participant Clock + participant RatingProviders + participant RC TROLIE + participant Neighbor RC 1 + participant Neighbor RC 2 + participant Neighbor RC 3 + + critical Establish polling for RLR snapshots + RC TROLIE->>Neighbor RC 1: + RC TROLIE->>Neighbor RC 2: + RC TROLIE->>Neighbor RC 3: + end + + RatingProviders->>RC TROLIE: Proposals + + Neighbor RC 2->>RC TROLIE: Return RLR snapshot + + Clock->>RC TROLIE: Trigger for RLR clearinghouse + RC TROLIE->>RC TROLIE: Generate RLR snapshot + + Neighbor RC 2->>RC TROLIE: Return RLR snapshot + + Clock->>RC TROLIE: Trigger for GLR clearinghouse + RC TROLIE->>RC TROLIE: Generate GLR snapshot + + +``` + +Each of the steps above deserves some more context. The following listing describes each event, referencing the +sequence numbers in the diagram above: + +1. The RC TROLIE server needs to poll for new RLRs against Neighbor RC 1. This leverages the [Conditional GET](./conditional-GET.md) pattern, against [getRegionalLimitsForecastSnapshot](../spec#tag/Forecasting/operation/getRegionalLimitsForecastSnapshot). +2. Same as #1 for Neighbor RC 2 +3. Same as #1 for Neighbor RC 3 +4. Ratings Providers submit proposals, or [LLRs](../concepts.md#locally-limiting-rating), to TROLIE to be processed by the clearinghouse. +5. Neighbor RC 2 may clear its RLRs before the RC TROLIE is ready to clear its own RLRs. The RC TROLIE must account for this in its design. +6. At an appointed time, the forecast clearinghouse for RLRs starts. All proposals for that forecast window _should_ have been submitted. +7. RC TROLIE generates a forecast snapshot with RLRs. It is available for other neighbor RCs to query. +8. Neighbor RC2 clears its RLRs, shortly after they are cleared in the RC TROLIE. RC TROLIE becomes aware of this for use in generating GLRs. +9. At an appointed time, the forecast clearinghouse for GLRs starts. All RLR forecasts from neighboring RCs _should_ have been created and be visible to the RC TROLIE. +10. RC TROLIE generates GLR snapshot, that makes deltas to its original RLR snapshot, accommodating the RLR snapshots it received from Neighbor RCs 1 and 2. Note that it never received anything from RC 3. This is a contingency that the RC TROLIE must handle. If RC 3 doesn't generate a forecast on time, then the RC TROLIE should be explicitly aware of that and engage in whatever recourse logic necessary to handle missing data from RC 3. + +# Reconciling Real-Time ClearingHouses +Reconciling forecast ratings is particularly challenging, because the difference between RLRs and +GLRs must be reconciled for each discrete [Forecast Window](./forecast-windows.md). + +Real-time however is more of an eventually consistent flow, constantly converging. This is because +there is no "target" window for a given rating. Rather, the value of the rating in use _now_ is +constantly being updated, based on the best knowledge a given RC has about the RLRs of the other +RC. Like forecast, there is a dedicated operation +[getRegionalRealTimeLimits](../spec#tag/Real-Time/operation/getRegionalRealTimeLimits) to facilitate +polling by the peers. However, rather than wait for new RLR values, the clearinghouse can +immediately generate new GLRs. + +See the following sequence for an example: + +```mermaid +sequenceDiagram + participant Clock + participant RatingProviders + participant RC TROLIE + participant Neighbor RC + + critical Establish polling for RLR snapshots + RC TROLIE->>Neighbor RC: + end + + RatingProviders->>RC TROLIE: Proposals + + Neighbor RC->>RC TROLIE: Return RLR snapshot + + Clock->>RC TROLIE: Trigger for clearinghouse + Note left of Clock: Time T + RC TROLIE->>RC TROLIE: Generate RLR snapshot based on proposals + RC TROLIE->>RC TROLIE: Generate GLR snapshot based on best known RLRs + + RatingProviders->>RC TROLIE: Proposals + + Neighbor RC->>RC TROLIE: Return RLR snapshot + + Clock->>RC TROLIE: Trigger for clearinghouse + Note left of Clock: Time T + 1 + RC TROLIE->>RC TROLIE: Generate RLR snapshot based on proposals + RC TROLIE->>RC TROLIE: Generate GLR snapshot based on best known RLRs + +``` + +At any given time, the clearinghouse is simply using the most recent version of the RLRs +it has from neighbors in determining the GLRs. During each clearinghouse run, the +age of neighboring RLRs, as well as real-time proposals, should be validated for age, +and recourse methodologies triggered if they are too old. + +# Monitoring the RC to RC Seam +The interactions described above can and should be monitored for latency, as well as the +absence of expected events such as missing RLR forecast snapshots from a particular peer. + +In addition, the derived seam monitoring set between peers, +described [here](./peer-monitoring-sets.md#seam-monitoring-sets), may be used to do more +thorough functional validations that multiple TROLIEs are configured and behaving +correctly. Specifically, the following conditions must be true: + +* Since both TROLIEs are generating seam monitoring sets, these monitoring sets should represent the same set of resources. The monitoring sets should have the same size, and each resource should have an alias that maps to the primary identifier or one of the aliases in the other monitoring set. +* For a given forecast window, the result of [getLimitsForecastSnapshot](../spec#tag/Forecasting/operation/getLimitsForecastSnapshot) (the GLRs) should be identical in each TROLIE. \ No newline at end of file diff --git a/docs/articles/peer-monitoring-sets.md b/docs/articles/peer-monitoring-sets.md index 4950a92..9c29719 100644 --- a/docs/articles/peer-monitoring-sets.md +++ b/docs/articles/peer-monitoring-sets.md @@ -10,7 +10,8 @@ using the workflow described in [Forecast Submittal](../example-narratives/submi However, two neighboring Transmission Providers, each running independent clearinghouses, will also have to share ratings. Each TROLIE server must be able to act as a client to achieve this coordination, -with each reaching out to one another. +with each reaching out to one another. These Transmission Providers also serve in the NERC role of +Reliability Coordinator (RC), which will be the term used throughout this article. This article specifically covers coordination of resource models on the seam between reliability coordinators, or really any two TROLIE implementations that can act as peers. It uses each RC's @@ -149,4 +150,4 @@ The seam monitoring set, as described above, would be derived by finding the ove `B-out`. This monitoring set has various uses in monitoring system behavior: * If the TROLIE implementation pre-configures the expected seam, then this configuration may be checked against the seam modeling set for differences, therefore spotting modeling errors. -* In future articles, we will show how the seam monitoring set may be used to monitor reconciliation of ratings across RCs. \ No newline at end of file +* [RC-to-RC Reconciliation](RC-to-RC-reconciliation) shows how the seam monitoring set may be used to monitor reconciliation of ratings across RCs. \ No newline at end of file diff --git a/docs/concepts.md b/docs/concepts.md index fbd676f..56061ff 100644 --- a/docs/concepts.md +++ b/docs/concepts.md @@ -172,7 +172,8 @@ to the limit "clearing" process internal to TROLIE server implementations that will integrate them into a final in-use rating set. In-use limit Snapshots are a distinct data set from Proposals. Proposals may be queried as well as submitted, so that the rating provider's original input data is always kept -separately from the in-use ratings. +separately from the in-use ratings. The values in rating proposals are also +known as locally limiting ratings or [LLRs](#locally-limiting-rating). ## Seasonal Ratings @@ -214,7 +215,9 @@ the provided static rating in lieu of an AAR for a specified period of time. As implied above, Snapshots are generated in TROLIE server implementations based on proposals and other inputs to generate in-use ratings for each Transmission Facility. TROLIE allows for ratings providers to fetch the latest snapshot, aka -the latest "version" of the ratings data. +the latest "version" of the ratings data. Depending on the context, limit +snapshots may represent either [RLRs](#regionally-limiting-rating) or +[GLRs](#globally-limiting-rating). ## Forecast Window @@ -254,3 +257,24 @@ possible, so that the data may be exchanged in a more accurate and precise manne such as "winter" may sometimes be provided as hints, seasonal rating schedules are ultimately defined in terms of start and end dates. Seasonal ratings in TROLIE are represented in terms of start and end dates, and TROLIE servers may decide how to enforce adherence to specific named seasons that they use. + +## Locally Limiting Rating +Locally Limiting Ratings (LLRs) refer to the output of individual ratings calculations, +pre-clearinghouse. LLRs are what is represented in rating [proposals](#ratings-proposals) in +TROLIE. Nominally, LLRs are used as RLRs, and ultimately as GLRs. This is ultimately subject +to the output of the clearinghouse. + +## Regionally Limiting Rating +Regionally Limiting Ratings (RLRs) refer to the output of rating clearinghouses for a particular Transmission +Provider. For most facilities, these are the ratings the system is operated to. These ratings +are the best they can be based on knowledge within the Transmission Provider's region. RLRs for most facilities +are naturally Globally Limiting Ratings (GLRs). However, for interties +between transmission providers, known colloquially as "tie lines", RLRs are incomplete. They need to be +reconciled with the appropriate neighbor clearinghouse to be known as GLRs. + +## Globally Limiting Rating +Globally Limiting Ratings (GLRs) refer to the resulting ratings that the power grid is operated to _after_ +all ratings have been coordinated. For most facilities, these should simply be RLRs passed through. However, +this is not the case for inter-ties across Transmission Providers, colloquially known as tie lines. RLRs on +tie-lines must be reconciled across the different regions in order to become global. The word "global" implies +that the rating now incorporates knowledge across regions.