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.

I-O structure

(Reference Heun et al. [-@Heun:2018], Section 2.2.4.)

With individual matrices

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"]]

From a matsindf-style data frame

Most 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.

Changes in final demand

(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.

Net energy analysis

(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]]

Efficiencies

(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.

Energy footprints

(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]]

Conclusion

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].

References



MatthewHeun/Recca documentation built on Feb. 9, 2024, 6:18 p.m.