Pyxidr

Executive summary

We show with this notebook (written in RMarkdown) how to use literate programming for accomplishing and presenting analyses.

In this notebook, we assume the client owns an efficient gas-fired power plant that is offered every day in the spot market. The dispatch team is responsible for scheduling the plant to maximize its margin while meeting all its dynamic constraints (e.g., start-up time, ramping, etc.).

However, a simple analysis shows the plant is not adequately scheduled as it often runs when the cash margin is negative or not at maximum capacity when the cash margin is positive.

The way the dispatch team schedules the plant suggests that the client sold the energy forward (i.e., bought forward natural gas and sold forward electricity) and, thus, does not look at the cash markets to improve the plant’s margin. If the dispatch team were scheduling the plant based on cash prices, they would have increased the cash margin by at least $1.63 million in 2015 and $2.90 million in 2016.

Analyses

Preamble

We define in this section all the critical parameters used by the notebook and source the associated scripts. We use scripts to make the notebook more natural to read in RMarkdown.

Gas-fired plant

We do all the analyses on gas-fired plant PP (“plant”) with the following attributes:

  • Type: CCGT
  • Fuel: Natural gas
  • Power min: 46.2 MW
  • Power max: 62.5 MW
  • Including duct: 77.5 MW
  • Efficiency at pmin: 45.2%
  • Efficiency: 46.7%
  • Efficiency of duct: 44.9%
  • Power market: PM
  • Variable O&M: 2.8
  • Gas transportation cost: $0.04/mmbtu
  • Carbon factor: 117.0 lb/mmbtu

Clean spark spread

The objective is to identify dispatch opportunities, i.e., determine when the plant should have been producing or not. The spark spread is the gross margin of a gas-fired power plant from selling a unit of electricity, having bought the natural gas required to produce this unit of electricity. A clean spark spread (“CSS”) is when we take into account the cost associated with emitting CO2 — not all markets charge yet for CO2 emissions.

CSS is defined as follows: \[ p^P - \left(p^G + tc + p^C \times \frac{cf}{2204.62}\right) \times \frac{hr}{10^3} - om \] where

  • \(cf\): Carbon factor (lb/mmbtu)
  • \(hr\): Heat rate (btu/kWh)
  • \(om\): Variable O&M ($/MWh)
  • \(p^C\): Carbon price in $/tonne
  • \(p^G\): Gas price in $/mmbtu
  • \(p^P\): Power price in $/MWh
  • \(tc\): Natural gas transportation cost ($/mmbtu)

This is how it is implemented:

We have included variable O&M costs in our definition of CSS to represent the opportunities better.

An efficient gas-fired plant takes time to start (e.g., 1 hour in a cold start) and has minimum uptime (e.g., 6 hours) and downtime to reduce the stress on the equipment. Therefore, we are going to group all the hours into on-peak and off-peak hours to take into account the lack of flexibility. Depending on the markets, on-peak hours are usually weekdays between 6 am and 10 pm. The rest of the hours are off-peak. We expect power prices to be higher during on-peak hours than off-peak ones.

The following graphic shows the distribution of CSS (on-peak/off-peak) where 71.8% of the on-peak periods have a positive CSS while 48.4% of the off-peak periods have a positive CSS.

We expect the plant not to produce when CSS is negative and produce at nominal capacity when CSS is large (e.g., higher than $5/MWh). However, the plant had produced above minimum load respectively 94.3% and 91.8% of the on-peak and off-peak periods when CSS was negative. Therefore, there are some opportunities for better dispatching the plant.

This X-Y plot shows, among others, how often the plant was producing when CSS was negative. The plant should have produced when the CSS was positive, but it could have been in maintenance.

Assessing the dispatch opportunity

As we have seen, the plant could have made more profits if it had been better dispatched (or dispatched against market prices). We roughly compute the opportunity as follows: \[ \sum_{t} \left(\max\{css_t(pmax)\times pmax, css_t(duct)\times duct, 0\} - css_t(gen_t)\times gen_t \right) \] where

  • \(css_t()\): Gross margin as a function of the energy produced in MW associated with period \(t\) ($/MWh)
  • \(duct\): Generating capcity including duct fired capacity (MW)
  • \(gen_t\): Actual generation for period \(t\) (MWh/h)
  • \(pmax\): Nominal generating capacity (MW)
  • \(t\): Period

We do this calculation over all on-peak and off-peak periods. As the following graphics show, the dispatch opportunities are fairly significant. It is important to note that a more granular shaping (e.g., by the hour) will lead to more significant opportunities.

Appendix

Vizualizing client’s data

It is always a good practice to visualize the raw data for spotting any discrepancies. Script analyses.R creates a data frame df_all that includes all the client’s data. We can dump this data frame in a CSV file that we can visualize in Tableau Public (or the paid version of Tableau).

Historical hourly spot (day ahead) power prices

On-peak prices are usually higher and more volatile than off-peak ones. Negative prices are due to excess of renewable energy, i.e., some thermal generating units are forced to shut down.

Showing a time series of 2+ years of hourly prices could be messy. The idea is to aggregate hourly prices in a meaningful way. This graphic is a boxplot that shows the price distribution associated with each month by period type (i.e., on-peak and off-peak). This way, we can easily see their variance and seasonality.

Historical spot daily gas prices

Historical spot daily carbon prices

Historical hourly generation

We expect generation to be lower during off-peak hours than on-peak ones. We use the same graphics used to show spot hourly power prices.

We observe that few hours have generation exceeding the installed capacity of 77.5. We have 2 hours in November 2015 and 2016 that represent the sum of 2 hours due to a time change. Dealing with hourly time series often involves dealing with time changes and time zones.

Copyright © 2019 Pyxidr. All rights reserved.