Getting started with REPRA

The Renewable Energy Probabilistic Resource Adequacy tool (REPRA) can be used to answer resource adequacy questions in the presence of variable generation (VG). This document shows an example of the basic capabilities of the package. The examples utilize part of the built-in datasets that are included in the package.

First load the package into memory, along with others that are used in this demonstration.

library(repra)
library(dplyr)
library(reshape2)
library(ggplot2)

Input data

All the calculations require two basic inputs, which are introduced in this section: an outage table and time series data.

Outage table

An outage table combines existing conventional generation and indicates the loss-of-load probability (LOLP) for different load levels. This object is created with the outage_table function, which requires input to be formatted as a data.frame with a column of capacity and expected forced outage rates (EFOR). For more information on the function, consult the help ?outage_table.

gens <- repragen %>%
  filter(Area == "AZ-NM-NV")
head(gens)
#>       Area Capacity   EFOR
#> 1 AZ-NM-NV    6.900 0.0000
#> 2 AZ-NM-NV    6.900 0.0000
#> 3 AZ-NM-NV    3.000 0.0000
#> 4 AZ-NM-NV  170.100 0.0380
#> 5 AZ-NM-NV  117.847 0.0380
#> 6 AZ-NM-NV  113.636 0.0248
out.table <- outage_table(gens)
head(out.table)
#>    Level     Area Capacity Capacity2         Prob         LOLP
#> 1:  Area AZ-NM-NV    66462     66462 2.755124e-09 1.001603e-06
#> 2:  Area AZ-NM-NV    66463     66463 2.762507e-09 1.004366e-06
#> 3:  Area AZ-NM-NV    66464     66464 2.769909e-09 1.007136e-06
#> 4:  Area AZ-NM-NV    66465     66465 2.777330e-09 1.009913e-06
#> 5:  Area AZ-NM-NV    66466     66466 2.784771e-09 1.012698e-06
#> 6:  Area AZ-NM-NV    66467     66467 2.792231e-09 1.015490e-06
#>         BaseEUE
#> 1: 0.000000e+00
#> 2: 2.755124e-09
#> 3: 8.272754e-09
#> 4: 1.656029e-08
#> 5: 2.762516e-08
#> 6: 4.147480e-08

An outage table can be easily plotted and summarized.

plot(out.table)

plot of chunk unnamed-chunk-4

summary(out.table)
#>    Level     Area   Max     Mean       SD
#> 1:  Area AZ-NM-NV 75700 73245.68 1008.435

Time series data

Time series need to be formatted with the format_timedata function before they can be used by other functions in the package. Time series must contain, at least, load data. Additional columns will be assumed to be VG and will be automatically be used in the other calculations.

tdata <- repratime %>% filter(Area == "AZ-NM-NV")
head(tdata)
#>       Area Time  Load CSP PV     Wind
#> 1 AZ-NM-NV    1 14204   0  0 1219.062
#> 2 AZ-NM-NV    2 13864   0  0 1355.490
#> 3 AZ-NM-NV    3 13778   0  0 1437.200
#> 4 AZ-NM-NV    4 13777   0  0 1183.795
#> 5 AZ-NM-NV    5 14233   0  0 1419.040
#> 6 AZ-NM-NV    6 15371   0  0 1876.116
td <- format_timedata(tdata)
head(td)
#>   Level     Area Time Day WinProb  Load CSP PV     Wind
#> 1  Area AZ-NM-NV    1   1       1 14204   0  0 1219.062
#> 2  Area AZ-NM-NV    2   1       1 13864   0  0 1355.490
#> 3  Area AZ-NM-NV    3   1       1 13778   0  0 1437.200
#> 4  Area AZ-NM-NV    4   1       1 13777   0  0 1183.795
#> 5  Area AZ-NM-NV    5   1       1 14233   0  0 1419.040
#> 6  Area AZ-NM-NV    6   1       1 15371   0  0 1876.116

Calculate metrics

To calculate reliability metrics, a time series with a NetLoad column must be provided to calculate_metrics. For example, here are the metrics for load (in this case the load is scaled or otherwise all values would be zero).

td2 <- td %>%
  mutate(NetLoad = 2.02 * Load)
calculate_metrics(td2, out.table)
#> Warning in anti_join_impl(x, y, by$x, by$y): joining character vector and
#> factor, coercing into character vector
#> Source: local data frame [1 x 6]
#> Groups: Level, Area
#> 
#>   Level     Area        LOLE       LOLH    PeakLOLP      EUE
#> 1  Area AZ-NM-NV 0.008366165 0.01385175 0.004194993 6.382079

The raw parameter allows us to see the actual values of LOLP and EUE for each hour.

cv <- calculate_metrics(td2, out.table, raw = TRUE)
#> Warning in anti_join_impl(x, y, by$x, by$y): joining character vector and
#> factor, coercing into character vector
cv %>%
  arrange(-Capacity) %>%
  as.data.frame() %>%
  head()
#>   Level     Area Capacity Capacity2         Prob         LOLP   BaseEUE
#> 1  Area AZ-NM-NV 69997.04     69997 8.126892e-06 0.0041949930 2.0355772
#> 2  Area AZ-NM-NV 69694.04     69694 4.641406e-06 0.0023037889 1.0788460
#> 3  Area AZ-NM-NV 69687.98     69687 4.580319e-06 0.0022714827 1.0628560
#> 4  Area AZ-NM-NV 69502.14     69502 3.211384e-06 0.0015569827 0.7131663
#> 5  Area AZ-NM-NV 69488.00     69488 3.125047e-06 0.0015125871 0.6917169
#> 6  Area AZ-NM-NV 68904.22     68904 9.570790e-07 0.0004336834 0.1850842
#>   Time Day WinProb  Load      CSP       PV      Wind       EUE
#> 1 4912 205       1 34652 1659.675 1688.453  71.77685 2.0357450
#> 2 5824 243       1 34502 1677.245 1631.764 183.98950 1.0789382
#> 3 4913 205       1 34499 1520.598 1197.492  53.90890 1.0650820
#> 4 4889 204       1 34407 1610.832 1325.818 180.82596 0.7133843
#> 5 4888 204       1 34400 1681.858 1706.066 178.11592 0.6917169
#> 6 5825 243       1 34111 1599.858 1200.851 225.46483 0.1851796

These metrics can also be calcuated after adding wind.

td2.wind <- td %>%
  mutate(NetLoad = 2.02 * Load - Wind)
calculate_metrics(td2.wind, out.table)
#> Warning in anti_join_impl(x, y, by$x, by$y): joining character vector and
#> factor, coercing into character vector
#> Source: local data frame [1 x 6]
#> Groups: Level, Area
#> 
#>   Level     Area        LOLE       LOLH    PeakLOLP      EUE
#> 1  Area AZ-NM-NV 0.006542352 0.01075845 0.003645922 4.907357

Calculate ELCC

Effective load carrying capacity (ELCC) is the maximum load that can be served at a give reliability metric (by default 1 day in 10 years daily LOLE). For this calculations, the load shape is modified until the desired level is reached. For more information on this process consult the help page for calculate_elcc.

elcc <- calculate_elcc(td, out.table)
#> Warning in anti_join_impl(x, y, by$x, by$y): joining character vector and
#> factor, coercing into character vector
as.data.frame(elcc)
#>   Level     Area Metric Objective ActualObj     ErrorObj Multiplier
#> 1  Area AZ-NM-NV   LOLE       0.1 0.1000443 0.0004429102   2.133781
#>       ELCC              VG LoadMethod      LOLE      LOLH   PeakLOLP
#> 1 73939.77 CSP + PV + Wind Flat block 0.1000443 0.3025853 0.02620607
#>        EUE
#> 1 151.9246

By default, ELCC is calculated with all the available VG data. The following example takes the series Wind out of the calculations.

elcc2 <- calculate_elcc(td, out.table, ignore = "Wind")
#> Warning in anti_join_impl(x, y, by$x, by$y): joining character vector and
#> factor, coercing into character vector
as.data.frame(elcc2)
#>   Level     Area Metric Objective ActualObj     ErrorObj Multiplier
#> 1  Area AZ-NM-NV   LOLE       0.1 0.1000267 0.0002674853   2.129072
#>       ELCC       VG LoadMethod      LOLE      LOLH   PeakLOLP      EUE
#> 1 73776.59 CSP + PV Flat block 0.1000267 0.3030752 0.02183544 151.2771

ELCC can be calculated for different metrics and different objective values.

elcc3 <- calculate_elcc(td, out.table, obj.metric = "LOLH", obj.value = 1.0)
#> Warning in anti_join_impl(x, y, by$x, by$y): joining character vector and
#> factor, coercing into character vector
as.data.frame(elcc3)
#>   Level     Area Metric Objective ActualObj     ErrorObj Multiplier
#> 1  Area AZ-NM-NV   LOLH         1  1.000064 6.448394e-05   2.153052
#>       ELCC              VG LoadMethod      LOLE     LOLH   PeakLOLP
#> 1 74607.57 CSP + PV + Wind Flat block 0.3171705 1.000064 0.07408182
#>        EUE
#> 1 544.8686

Calculate capacity value

Capacity value is the increase in ELCC (measured with the same risk level) when a new resource is added to the system. The capacity_value function automatically calculates capacity value for each of the VG time series and adds it to the load in order.

cv <- capacity_value(td, out.table)
#> Warning in anti_join_impl(x, y, by$x, by$y): joining character vector and
#> factor, coercing into character vector
#> Warning in anti_join_impl(x, y, by$x, by$y): joining character vector and
#> factor, coercing into character vector
#> Warning in anti_join_impl(x, y, by$x, by$y): joining character vector and
#> factor, coercing into character vector
#> Warning in anti_join_impl(x, y, by$x, by$y): joining character vector and
#> factor, coercing into character vector
#> Warning in anti_join_impl(x, y, by$x, by$y): joining character vector and
#> factor, coercing into character vector
as.data.frame(cv)
#>   Level     Area Metric Objective  ActualObj      ErrorObj Multiplier
#> 1  Area AZ-NM-NV   LOLE       0.1 0.10002850  2.850468e-04   2.049591
#> 2  Area AZ-NM-NV   LOLE       0.1 0.09999567 -4.327014e-05   2.095526
#> 3  Area AZ-NM-NV   LOLE       0.1 0.10002675  2.674853e-04   2.129072
#> 4  Area AZ-NM-NV   LOLE       0.1 0.10004429  4.429102e-04   2.133781
#>       ELCC              VG LoadMethod       LOLE      LOLH   PeakLOLP
#> 1 71022.41                 Flat block 0.10002850 0.2385582 0.02655571
#> 2 72614.15             CSP Flat block 0.09999567 0.2594986 0.02371214
#> 3 73776.59        CSP + PV Flat block 0.10002675 0.3030752 0.02183544
#> 4 73939.77 CSP + PV + Wind Flat block 0.10004429 0.3025853 0.02620607
#>        EUE   CVTech        CV
#> 1 120.7266 BaseELCC        NA
#> 2 129.9683      CSP 1591.7409
#> 3 151.2771       PV 1162.4344
#> 4 151.9246     Wind  163.1822

This information can be reformatted and presented in a more pleseant format. It can also be easily plotted.

dcast(cv, Level + Area + Metric + Objective ~ CVTech, value.var = "CV")
#>   Level     Area Metric Objective BaseELCC      CSP       PV     Wind
#> 1  Area AZ-NM-NV   LOLE       0.1       NA 1591.741 1162.434 163.1822
ggplot(cv, aes(x = paste(Level, Area, sep = ", "), weight = CV, fill = CVTech)) +
  geom_bar() +
  labs(x = "Area", y = "Capacity Value (MW)", fill = "Type")

plot of chunk unnamed-chunk-13

The previous example calculated the cumulative capacity value by iteratively adding VG profiles. An alternative would be to calculate the capacity value by removing only one VG profile from the total mix. The parameter marginal is used to change this behavior.

cv.mar <- capacity_value(td, out.table, marginal = TRUE)
#> Warning in anti_join_impl(x, y, by$x, by$y): joining character vector and
#> factor, coercing into character vector
#> Warning in anti_join_impl(x, y, by$x, by$y): joining character vector and
#> factor, coercing into character vector
#> Warning in anti_join_impl(x, y, by$x, by$y): joining character vector and
#> factor, coercing into character vector
#> Warning in anti_join_impl(x, y, by$x, by$y): joining character vector and
#> factor, coercing into character vector
#> Warning in anti_join_impl(x, y, by$x, by$y): joining character vector and
#> factor, coercing into character vector
as.data.frame(cv.mar)
#>   Level     Area Metric Objective ActualObj     ErrorObj Multiplier
#> 1  Area AZ-NM-NV   LOLE       0.1 0.1000317 3.171771e-04   2.092735
#> 2  Area AZ-NM-NV   LOLE       0.1 0.1000094 9.390268e-05   2.099799
#> 3  Area AZ-NM-NV   LOLE       0.1 0.1000267 2.674853e-04   2.129072
#>       ELCC         VG LoadMethod      LOLE      LOLH   PeakLOLP      EUE
#> 1 72517.45  PV + Wind Flat block 0.1000317 0.2593099 0.03083549 131.4253
#> 2 72762.25 CSP + Wind Flat block 0.1000094 0.2550222 0.02708797 128.5949
#> 3 73776.59   CSP + PV Flat block 0.1000267 0.3030752 0.02183544 151.2771
#>   CVTech        CV
#> 1    CSP 1422.3176
#> 2     PV 1177.5196
#> 3   Wind  163.1822