knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
library(dplyr) library(matsbyname) library(matsindf) library(Recca) library(tibble) library(tidyr)
```{=tex} \newcommand{\transpose}[1]{#1^\mathrm{T}} \newcommand{\inverse}[1]{#1^{\mathrm{-}1}} \newcommand{\mat}[1]{\mathbf{#1}} \newcommand{\colvec}[1]{\mathbf{#1}} \newcommand{\rowvec}[1]{\transpose{\colvec{#1}}} \newcommand{\inversetranspose}[1]{\transpose{\left( \inverse{\mat{#1}} \right)}} \newcommand{\transposeinverse}[1]{\inverse{\left( \transpose{\mat{#1}} \right)}} \newcommand{\hatinv}[1]{\inverse{\widehat{#1}}}
```{=tex} \newcommand{\matwithdims}[3]{\underset{\mathrm{#2} \times \mathrm{#3}}{\mat{#1}}} \newcommand{\colvecwithdims}[2]{\underset{\mathrm{#2} \times 1}{\colvec{#1}}}
```{=tex} \newcommand{\Lpp}{\matwithdims{L}{p}{p}} \newcommand{\Lip}{\matwithdims{L}{i}{p}}
## Introduction `Recca` (`R` Energy Conversion Chain Analysis) is an `R` package that enables energy and exergy analysis of energy conversion chains. `Recca` makes extensive use of a matrix-based Physical Supply Use Table (PSUT) analysis technique that first appeared in [Heun et al. [-@Heun:2018]](https://doi.org/10.1016/j.apenergy.2018.05.109). This vignette walks through many of the calculations from [Heun et al. [-@Heun:2018]](https://doi.org/10.1016/j.apenergy.2018.05.109), guided by section numbers from the paper. We begin by discussing the design philosophy of the `Recca` package, followed by a discussion of the PSUT matrices that comprise an energy conversion chain (ECC). Thereafter, calculation of the input-output structure of an ECC is demonstrated. Finally, advanced calculations are shown, including changes in final demand, net energy analysis, industry efficiencies, and energy footprints. ## Design philosophy The functions in `Recca` are flexibly designed and useful in many situations. `Recca`'s flexibility stems from its extensive use of the `matsbyname` and `matsindf` packages under the hood. Inputs to most `Recca` functions can be any one of: 1. matrices (with individual matrices as arguments to `Recca` functions), 2. a list as the first argument (with names in the list indicating argument names), or 3. a data frame (with names of data frame columns, as strings, as arguments to `Recca` functions). Outputs are either named matrices in a list (for 1 and 2 above) or named columns appended to the input data frame (for 3 above). Argument names for matrices follow a standard nomenclature. It is recommended that the default matrix names be used whenever possible, thereby allowing cleaner code. ## PSUT matrices (Reference [Heun et al. [-@Heun:2018]](https://doi.org/10.1016/j.apenergy.2018.05.109), Section 2.2.2.) For the examples that follow, we'll use the `UKEnergy2000tidy` data frame. Each row of `UKEnergy2000tidy` data frame represents another datum for a portion of the ECC for the UK in 2000. `UKEnergy2000tidy` is in a format similar to data from the IEA or other organizations. For data in the format of `UKEnergy2000tidy`, we can create `S_units` matrices for each grouping using the `S_units_from_tidy()` function. ```r library(tibble) S_units <- UKEnergy2000tidy %>% dplyr::group_by(Country, Year, Energy.type, Last.stage) %>% S_units_from_tidy() tibble::glimpse(S_units)
And we can identify which entries belong in the resource ($\mathbf{R}$),
make ($\mathbf{V}$), use ($\mathbf{U}$), and final demand ($\mathbf{Y}$)
matrices with the IEATools::add_psut_matnames()
and
IEATools::add_row_col_meta()
functions.
WithNames <- UKEnergy2000tidy %>% # Add a column indicating the matrix in which this entry belongs (U, V, or Y). IEATools::add_psut_matnames() %>% # Add metadata columns for row names, column names, row types, and column types. IEATools::add_row_col_meta() %>% # Eliminate columns we no longer need dplyr::select(-Ledger.side, -Flow.aggregation.point, -Flow, -Product) %>% dplyr::mutate( # Ensure that all energy values are positive, as required for analysis. E.dot = abs(E.dot) ) head(WithNames)
After identifying the matrices, rownames, colnames, rowtypes, and
coltypes, we can collapse all data to matrices and add a unit summation
matrix (S_units
).
AsMats <- WithNames %>% # Collapse to matrices using functions in the matsindf package dplyr::group_by(Country, Year, Energy.type, Last.stage, matnames) %>% matsindf::collapse_to_matrices(matnames = "matnames", matvals = "E.dot", rownames = "rownames", colnames = "colnames", rowtypes = "rowtypes", coltypes = "coltypes") %>% dplyr::rename(matrix.name = matnames, matrix = E.dot) %>% tidyr::spread(key = matrix.name, value = matrix) %>% # Do a little more cleanup dplyr::mutate( # Create full U matrix U = matsbyname::sum_byname(U_feed, U_EIOU), # Create r_EIOU, a matrix that identifies the ratio of EIOU to other energy consumed. r_EIOU = matsbyname::quotient_byname(U_EIOU, U), r_EIOU = matsbyname::replaceNaN_byname(r_EIOU, val = 0) ) %>% dplyr::select(-U_EIOU, -U_feed) %>% # Add S_units matrices dplyr::left_join(S_units, by = c("Country", "Year", "Energy.type", "Last.stage")) %>% tidyr::gather(key = matrix.name, value = matrix, R, U, V, Y, r_EIOU, S_units) tibble::glimpse(AsMats)
The AsMats
data frame is essentially the same as the
Recca::UKEnergy2000mats
data frame. The remainder of this vignette
uses the UKEnergy2000mats
data frame.
(Reference Heun et al. [-@Heun:2018], Section 2.2.4.)
To determine the I-O structure of an ECC, use the calc_io_mats()
function.
library(tidyr) mats <- UKEnergy2000mats %>% tidyr::spread(key = matrix.name, value = matrix) %>% # Put rows in a natural order dplyr::mutate( Last.stage = factor(Last.stage, levels = c("Final", "Useful", "Services")), Energy.type = factor(Energy.type, levels = c("E", "X")) ) %>% dplyr::arrange(Last.stage, Energy.type) # Use the calc_io_mats function with individual matrices, # each taken from the first row of the UKEnergy2000mats data frame. R <- mats$R[[1]] U <- mats$U[[1]] U_feed = mats$U_feed[[1]] V <- mats$V[[1]] Y <- mats$Y[[1]] S_units <- mats$S_units[[1]] IO_list <- calc_io_mats(R = R, U = U, U_feed = U_feed, V = V, Y = Y, S_units = S_units)
Most Recca
functions return a list when called with individual
matrices as arguments. The calc_io_mats()
function gives several I-O
matrices in its returned list.
class(IO_list) names(IO_list) IO_list[["y"]]
The same calculations can be performed by supplying a named list to
Recca
functions. In this approach, all original data are returned in
the list. So in this case, matrices $\mathbf{U}$, $\mathbf{V}$,
$\mathbf{Y}$, and $\mathbf{S_{units}}$ are also returned from the
calc_io_mats()
function. When a list is supplied to a Recca
function
in the .sutmats
argument, most other input arguments must be strings
that identify the names of appropriate entries in the .sutmats
list
containing named vectors or matrices. Helpfully, the default values for
other input arguments conform to a standard nomenclature. When using the
standard nomenclature, most Recca
functions can use the default
arguments for input and output items in the list.
IO_from_list <- calc_io_mats(list(R = R, U = U, U_feed = U_feed, V = V, Y = Y, S_units = S_units)) class(IO_from_list) names(IO_from_list) IO_from_list[["y"]]
matsindf
-style data frameMost Recca
functions can also operate on a matsindf
-style data
frame. (A matsindf
-style data frame has matrices in cells of a data
frame. See the matsindf
package for additional information.) When a
data frame is supplied to a Recca
function in the .sutmats
argument,
most other input arguments must be strings that identify the names of
appropriate columns in .sutmats
containing named vectors or matrices.
Helpfully, the default values for other input arguments conform to a
standard nomenclature. When using the standard nomenclature, most
Recca
functions can use the default arguments for input and output
columns. This approach yields very clean piped code, as shown below.
To illustrate the above features of Recca
functions, we'll apply the
calc_io_mats
function to the entire UKEnergy2000mats
data frame,
calculating appropriate I-O matrices for each row. Used in this way,
Recca
functions act like specialized dplyr::mutate()
functions, with
new columns added to the right side of the data frame supplied to the
.sutmats
argument.
IO_df <- mats %>% calc_io_mats()
By inspecting IO_df
, we can see, for example, that one $\mathbf{y}$
vector was calculated for each of the four rows of mats
. The same is
true for all I-O matrices calculated by calc_io_mats
.
class(IO_df) names(IO_df) glimpse(IO_df) IO_df[["y"]][[1]] IO_df[["y"]][[4]]
For the remainder of this vignette, operations will be performed on the
entire UKEnergy2000mats
data frame. But readers should remember that
functions can be called on named lists or individual matrices, as well.
(Reference Heun et al. [-@Heun:2018], Section 2.2.5.)
One of the first applications of input-output analysis was estimating
changes in industry outputs that would be required to meet new final
demand. Recca
allows similar calculations on energy conversion chains
with the function new_Y()
. Arguments to new_Y()
include matrices
that describe the input-output structure of the ECC and Y_prime
, the
new final demand matrix. new_Y()
calculates U_prime
and V_prime
matrices which represent the ECC that would be required to meet the new
final demand represented by Y_prime
.
Double_demand <- IO_df %>% dplyr::mutate( Y_prime = matsbyname::hadamardproduct_byname(2, Y) ) %>% new_Y() names(Double_demand) IO_df[["Y"]][[1]][ , c(1,2)] Double_demand[["Y_prime"]][[1]] IO_df[["U"]][[1]][ , c("Crude dist.", "Diesel dist.")] Double_demand[["U_prime"]][[1]][ , c("Crude dist.", "Diesel dist.")]
See the vignette for the new_*()
functions for
more details.
(Reference Heun et al. [-@Heun:2018], Section 3.1.)
The energy production system itself consumes energy, and important
metrics for energy conversion chain industries are energy return ratios
(ERRs). Recca
provides a function to calculate three ERRs, a gross
energy ratio (GER), a net energy ratio (NER), and the ratio of NER to
GER. GER is commonly called energy return on investment (EROI). (See
Brandt & Dale [-@Brandt:2011].)
These ERRs can be calculated for a variety of system boundaries. ERRs
for the $\gamma$ system boundary can be calculated readily using the
calc_ERRs_gamma()
function. All three ERRs are calculated at the same
time. The ERRs are NA
for industries in which inputs or outputs are
unit-inhomogeneous. The ERRs are Inf
for industries that make an
energy product without consuming any energy from another processing
chain (such as the Elect. grid). The results below are identical to Fig.
6 in Heun et al.
[-@Heun:2018].
ERRs <- IO_df %>% calc_ERRs_gamma() ERRs$ger_gamma[[1]] ERRs$ner_gamma[[1]] ERRs$r_gamma[[1]]
(Reference Heun et al. [-@Heun:2018], Section 3.2.)
The efficiency of every industry in the ECC can be calculated quickly
with the calc_eta_i()
function, which creates a column named eta_i
(by default) at the right of the data frame. If a particular ECC has
industries whose inputs or outputs are unit inhomogeneous, the eta_i
vector will have NA
values in the appropriate places. The results
below are identical to Fig. 9 in Heun et al.
[-@Heun:2018].
etas <- IO_df %>% calc_eta_i() names(etas) etas[["eta_i"]][[1]] etas[["eta_i"]][[3]] # NAs indicate inhomogeneous units on inputs or outputs.
(Reference Heun et al. [-@Heun:2018], Section 3.3.)
Final demand for energy contains embodied primary energy, the sum of all
primary energy consumed and wasted throughout the ECC in the process of
satisfying that final demand. Recca
provides two functions to
calculate embodied primary energy and important ratios, namely
calc_embodied_mats()
and calc_embodied_etas()
.
The function calc_embodied_mats()
calculates embodied energy in final
demand products ($p$) and final demand sectors ($s$).
Outputs from calc_embodied_mats()
include the following matrices:
+--------------------------------------+-----------------------------------------------------------------+ | Matrix | Description (rows$\times$columns) | +=====================================:+:================================================================+ | $\mathbf{G} = | Industry and resource stocks output requirements for final | | \mathbf{G}R + \mathbf{G}_V$ | demand ($(r + i) \times p$) | +--------------------------------------+-----------------------------------------------------------------+ | $\mathbf{G}_R = | Resource stocks output requirements for final demand | | \mathbf{R} | ($r \times p$) | | \widehat{\mathbf{q}}^{\mathrm{-}1} | | | \underset{\mathrm{p} \times | | | \mathrm{p}}{\mathbf{L}} | | | \hat{\mathbf{y}}$ | | +--------------------------------------+-----------------------------------------------------------------+ | $\mathbf{G}_V = | Industry output requirements for final demand ($i \times p$) | | \underset{\mathrm{i} \times | | | \mathrm{p}}{\mathbf{L}} | | | \widehat{\mathbf{y}}$ | | +--------------------------------------+-----------------------------------------------------------------+ | $\mathbf{H} = | Industry and resource stocks output requirements for final | | \mathbf{H}_R + \mathbf{H}_V$ | demand sectors ($(r + i) \times s$) | +--------------------------------------+-----------------------------------------------------------------+ | $\mathbf{H}_R = | Resource stocks output requirements for final demand sectors | | \mathbf{R} | ($r \times s$) | | \widehat{\mathbf{q}}^{\mathrm{-}1} | | | \underset{\mathrm{p} \times | | | \mathrm{p}}{\mathbf{L}}\mathbf{Y}$ | | +--------------------------------------+-----------------------------------------------------------------+ | $\mathbf{H}_V = | Industry output requirements for final demand sectors | | \underset{\mathrm{i} \times | ($i \times s$) | | \mathrm{p}}{\mathbf{L}}\mathbf{Y}$ | | +--------------------------------------+-----------------------------------------------------------------+ | $\mathbf{E} = | Energy or services produced ($+$) or consumed ($-$) per unit | | [ (\mathbf{R} + | output by industries (in columns) ($p \times i$) | | \mathbf{V})^\mathrm{T} - | | | \mathbf{U}{feed} ] | | | \widehat{(\mathbf{r} + | | | \mathbf{g})}^{-1}$ | | +--------------------------------------+-----------------------------------------------------------------+ | $\mathbf{r} = | Row sums of $\mathbf{R}$ matrix; works only when $\mathbf{R}$ | | \bar{\mathbf{R}} \mathbf{i}$ | is unit-homogeneous | +--------------------------------------+-----------------------------------------------------------------+ | $\mathbf{g} = | Row sums of $\mathbf{V}$ matrix; works only when $\mathbf{V}$ | | \bar{\mathbf{V}} \mathbf{i}$ | is unit-homogeneous | +--------------------------------------+-----------------------------------------------------------------+ | $\mathbf{e}_i$ | Rows of $\mathbf{E}$; subscript $i$ indicates energy products | +--------------------------------------+-----------------------------------------------------------------+ | $\mathbf{Q}_i = | Sources (positive entries) and | | \widehat{\mathbf{e}_i} \mathbf{G}$ | consumption (negative entries) by industries (in rows) | | | of embodied energy products (subscript $i$) in consumed | | | energy products (in columns) | +--------------------------------------+-----------------------------------------------------------------+ | $\mathbf{Q}_i^+$ | $\mathbf{Q}_i$ with negative entries set to zero | +--------------------------------------+-----------------------------------------------------------------+ | $\mathbf{i} \mathbf{Q}_i^+$ | Column sums (to form row vectors) of $\mathbf{Q}_i^+$ | | | (embodied product $\times$ embodying products | +--------------------------------------+-----------------------------------------------------------------+ | $\mathbf{M}_p$ | Each row is one $\mathbf{i} \mathbf{Q}_i^+$ to | | | show embodied energy products in each embodying energy product | | | (embodied products $\times$ embodying products) | +--------------------------------------+-----------------------------------------------------------------+ | $\mathbf{M}_s = \mathbf{M}_p | Embodied energy products consumed by final demand sectors | | \hat{\mathbf{q}}^{-1} \mathbf{Y}$ | (embodied products $\times$ consuming final demand sectors) | +--------------------------------------+-----------------------------------------------------------------+
calc_embodied_mats()
also calculates $\mathbf{F}{footprint}$ and
$\mathbf{F}{ef!fects}$ matrices, which answer the questions
(respectively) "What is the fractional composition of embodied energy of
each final demand energy type?" and "What is the fractional destination
of a given upstream energy product?" The calculations can be performed
for each final demand product or each final demand sector. The following
table describes these matrices.
+--------------------------------------------+-----------------------------------------------------------------+ | Matrix | Description | +===========================================:+:================================================================+ | $\mathbf{F}{footprint,p} = | Each final demand product (columns) contains embodied energy. | | \mathbf{M}_p | On a fractional basis, where does that embodied energy come | | (\widehat{\mathbf{i} \mathbf{M}_p})^{-1}$ | from (rows)? Columns sum to 1. | +--------------------------------------------+-----------------------------------------------------------------+ | $\mathbf{F}{ef!fects,p} = | Each upstream energy product (rows) becomes embodied somewhere. | | (\widehat{\mathbf{M}p} \mathbf{i})^{-1} | On a fractional basis, where does that upstream energy become | | \mathbf{M}_p$ | embodied (columns)? Rows sum to 1. | +--------------------------------------------+-----------------------------------------------------------------+ | $\mathbf{F}{footprint,s} = | Each final demand sector (columns) consumes embodied energy. On | | \mathbf{M}s | a fractional basis, where does the consumed embodied energy | | (\widehat{\mathbf{i} \mathbf{M}_s})^{-1}$ | come from (rows)? Columns sum to 1. | +--------------------------------------------+-----------------------------------------------------------------+ | $\mathbf{F}{ef!fects,s} = | Each embodied upstream energy product (rows) is consumed by a | | (\widehat{\mathbf{M}_s} \mathbf{i})^{-1} | final demand sector. On a fractional basis, where is that | | \mathbf{M}_s$ | embodied upstream energy consumed (columns)? Rows sum to 1. | +--------------------------------------------+-----------------------------------------------------------------+
Finally, embodied energy efficiencies can be calculated as final demand
energy divided by embodied energy. Again, efficiencies can be calculated
for each final demand product or each final demand sector. The
calc_embodied_etas()
function does this computation.
+------------------------------------------------------+-----------------------------------------------------------------+ | Matrix | Description | +=====================================================:+:================================================================+ | $\eta_p = (\widehat{\mathbf{G}^\mathrm{T} | Final demand product (rows) divided by embodied primary | | \mathbf{s}_r})^{-1} \mathbf{y}$ | energy of that final demand product | +------------------------------------------------------+-----------------------------------------------------------------+ | $\eta_s = (\widehat{\mathbf{s}_r \mathbf{H}})^{-1} | Energy consumed by final demand sector (rows) divided by | | (\mathbf{iY})^{\mathrm{T}}$ | embodied energy input to the final demand sector | +------------------------------------------------------+-----------------------------------------------------------------+
Note: $\mathbf{s}_r$ is a selection vector for resource industries.
primary_machine_names <- c("Resources - Crude", "Resources - NG") embodied_mats <- IO_df %>% dplyr::mutate( U_EIOU = matsbyname::hadamardproduct_byname(r_EIOU, U) ) %>% calc_embodied_mats() %>% calc_embodied_etas(primary_machine_names = primary_machine_names) names(embodied_mats)
Figure 15 in Heun et al.
[-@Heun:2018] shows
primary-to-services energetic efficiencies for the ECC in the 3rd row of
IO_df
. The following code extracts those results. Rows of the vector
give final demand services and their units. The column gives
efficiencies in units of service per ktoe of energy.
embodied_mats$eta_p[[3]]
This vignette demonstrated the use of the Recca
package. Recca
provides many useful functions for analyzing energy conversion chains
within the PSUT framework first described in Heun et al.
[-@Heun:2018].
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.