This is a tutorial to show the use and mode of operation of the Environmental Impacts toolbox from the ADVANCE project. The toolbox is freely available from the ADVANCE project site.
The only data requirement are the results from an integrated assessment model (IAM) that detail electricity production, installed capacity, and capacity additions of power production technologies.
These data need to be in the format supplied by the IIASA databases, e.g. the AR5 database.
The toolbox produces three output files in the same format as the IAM inputs.
The first contains the indirect energy requirements and the environmental impacts by region, technology, and life-cycle phase (construction and operation, end-of-life impacts are generally very small and included with construction), for all models and scenarios of the input.
The other two contain energy requirements and environmental impacts separately, for all different technology variants represented in the LCA data (e.g. different types of PV cells) and allow for the estimation of uncertainty ranges.
Before running the ADVANCE_Toolbox_EI.R
script, some small modifications in the configuration
section may be necessary.
IAM_results_file <- "./data/REMIND_example_data.csv"
Baseline
, which assumes a business-as-usual trajectory without concerted climate change mitigation effort, and BLUE_Map
, which assumes changes to the structure and efficiency of (industrial) processes and power sector technology improvements. BLUE_Map
is used for all climate policy scenarios, regardless policy instruments or level of ambition.TL$scenarios <- inline_data_frame(
"THEMIS; IAMs",
"Baseline; ADV_WP5_Base",
"BLUE_Map; ADV_WP5_P240_FullTech")
./data/NTNU_LCA_coefficients.xlsx
.TL$regions <- inline_data_frame(
# "MESSAGE-GLOBIOM_1.0" added for illustration
"THEMIS; REMIND 1.7; MESSAGE-GLOBIOM_1.0",
"AME; AFR; AFR",
"AME; MEA; MEA",
"AS; OAS; PAS",
...)
TL$technologies <- inline_data_frame(
"THEMIS; IAMs",
...
"Wind|onshore; Wind|Onshore",
"Wind|offshore; Wind|Offshore",
"Solar|CSP; Solar|CSP",
"Solar|PV; Solar|PV")
(Scenarios and technologies must be identical across models, as in the IIASA databases, while regions can differ.)
You can now run the toolbox.
After loading required packages and configuration, the IAM data and the LCA coefficients from the THEMIS model are loaded and converted into the proper format for use. If the data has not changed, cached versions of the data will be used.
# ---- load LCA and IAM data ----
if (-1 == file.access("./cache/LCA_coefficients.Rdata")
| force_tidy_LCA
| (max(file.info(c("./scripts/tidy_LCA_data.R",
LCA_coefficients_file))$mtime)
> file.info("./cache/LCA_coefficients.Rdata")$mtime)) {
cat("Processing LCA coefficients\n")
source("./scripts/tidy_LCA_data.R")
} else {
load("./cache/LCA_coefficients.Rdata")
}
if (-1 == file.access("./cache/IAM_data.Rdata")
| force_tidy_LCA
| (max(file.info(c("./scripts/tidy_IAM_data.R", IAM_results_file))$mtime)
> file.info("./cache/IAM_data.Rdata")$mtime)) {
cat("\nProcessing IAM results\n")
source("./scripts/tidy_IAM_data.R")
} else {
load("./cache/IAM_data.Rdata")
}
The script tidy_IAM_data.R
returns two tables:
IAM.Electricity.Production
contains the electricity production in seven columns:
model
: lists the IAM model.scenario
: lists the IAM scenario.region
: lists the IAM region.technology
: lists the type of power plant.unit
: is always EJ/year.period
: lists model time-step.value
: holds the electricity production.car::some(IAM.Electricity.Production)
IAM.Capacity
contains the currently installed capacities and new capacity additions of the power plants in much the same format, except that
phase
: distinguishes between Capacity
(in GW) and Capacity Additions
(in GW/year).car::some(IAM.Capacity)
The script tidy_LCA_data
returns three tables:
energy.requirements
contains the coefficients of indirect energy requirements for the construction, operation, and end-of-life of power generation capacities and has 11 columns:
scenario
: lists the IAM scenario.region
: lists the IAM region.technology
: lists the power sector technology.technology.variant
: distinguishes between different variants of technologies with different LCA coefficients (e.g. different types of PV cells). The mix
variant is an average weighted by assumed likely shares of future deplyment of the different variants.phase
: lists the life-cycle phase (Construction
, Operation
, or End-of-life
).quantity
: lists the service the energy is consumed for. Either a direct or not-specified energy service (Energy
), or one of three key industry services (Cement and concrete
, Iron and steel
, Freight transport
). This allows for further extensions to use model endogenous energy intensities for these service, if available.energy.carrier
: lists the consumed final energy carrier (to calculate indirect CO2 emissions).unit.numerator
and unit.denominator
: list the unit of the coefficient, in a way to easily adjust them during calculations.period
: list the model time-step. LCA coefficients are available from THEMIS for 2010, 2030, and 2050. Time-steps between those are interpolated linearly, while the coefficients are kept constant before and after, on the 2010 or 2050 level, respectively.value
: holds the value of the coefficient.car::some(energy.requirements)
environmental.impacts
contains the environmental impacts and has generally the same format as energy.requirements
, except that
impact
: lists the impact category, namely
MAgPIE.luluc.emissions
contains specific land-use and land-use change (LULUC) change emissions of CO2, CH4, and N2O for different regions and biomass production regimes derived from the MAgPIE model.For increased clarity in this tutorial, we limit the data to two technologies, two impacts, two life-cycle phases as well as one combination of model/scenario/region/period. We also drop the unused dimensions when showing data.
select_technologies <- c('Coal|w/o CCS', 'Solar|PV')
IAM.Capacity <- IAM.Capacity %>%
filter('REMIND 1.7' == model,
'ADV_WP5_P240_FullTech' == scenario,
'IND' == region,
2025 == period,
technology %in% select_technologies)
IAM.Capacity %>%
select(technology, phase, unit, value)
IAM.Electricity.Production <- IAM.Electricity.Production %>%
filter('REMIND 1.7' == model,
'ADV_WP5_P240_FullTech' == scenario,
'IND' == region,
2025 == period,
technology %in% select_technologies)
IAM.Electricity.Production %>%
select(technology, unit, value)
energy.requirements <- energy.requirements %>%
filter('ADV_WP5_P240_FullTech' == scenario,
'IN' == region,
'mix' == technology.variant,
2025 == period,
technology %in% select_technologies,
quantity %in% c('Energy', 'Iron'),
phase %in% c('Construction', 'Operation'))
energy.requirements %>%
unite(unit, unit.numerator, unit.denominator, sep = '/') %>%
select(technology, phase, quantity, unit, value)
environmental.impacts <- environmental.impacts %>%
filter('ADV_WP5_P240_FullTech' == scenario,
'IN' == region,
'mix' == technology.variant,
2025 == period,
technology %in% select_technologies,
impact %in% c('Aluminium', 'Human toxicity'),
phase %in% c('Construction', 'Operation'))
environmental.impacts %>%
unite(unit, unit.numerator, unit.denominator, sep = '/') %>%
select(technology, impact, phase, unit, value)
The energy requirements are calculated in the script calculate_energy_requirements.R
.
Energy requirements for construction (in which those of the end-of-life are included) are calculated by joining the two tables of capacity additions
IAM.Capacity %>%
filter(phase == "Capacity Additions") %>%
select(technology, capacity.additions = value, unit)
and the LCA coefficients
energy.requirements %>%
filter(phase %in% c("Construction", "End-of-life")) %>%
group_by(scenario, region, technology, technology.variant, quantity,
energy.carrier, unit.numerator, unit.denominator, period) %>%
summarise(energy.requirements = sum(value)) %>%
ungroup() %>%
unite(unit, unit.numerator, unit.denominator, sep = '/') %>%
select(technology, quantity, energy.carrier, energy.requirements, unit)
and multiplying the capacity additions with the LCA coefficients 1.
inner_join(
IAM.Capacity %>%
filter(phase == "Capacity Additions") %>%
select(technology, capacity.additions = value, unit),
energy.requirements %>%
filter(phase %in% c("Construction", "End-of-life")) %>%
group_by(scenario, region, technology, technology.variant, quantity,
energy.carrier, unit.numerator, unit.denominator, period) %>%
summarise(energy.requirements = sum(value)) %>%
ungroup() %>%
select(technology, quantity, energy.carrier,
unit.numerator, unit.denominator, energy.requirements),
by = 'technology'
) %>%
# GJ/MW * GW/a * 1000 MW/GW = GJ/a
mutate(value = energy.requirements * capacity.additions * 1e3,
phase = "Construction",
unit.denominator = "yr") %>%
unite(unit, unit.numerator, unit.denominator, sep = '/') %>%
select(technology, phase, quantity, energy.carrier, value, unit)
Energy requirements for operation are calculated in a similar manner using capacity data for technologies that don’t use fuels,
IAM.Capacity %>%
filter(phase == "Capacity") %>%
select(technology, capacity = value, unit)
energy.requirements %>%
filter(phase == "Operation",
unit.denominator == "MW/yr") %>%
select(technology, quantity, energy.carrier,
energy.requirements = value, unit.numerator, unit.denominator)
inner_join(
IAM.Capacity %>%
filter(phase == "Capacity") %>%
select(technology, capacity = value, unit),
energy.requirements %>%
filter(phase == "Operation",
unit.denominator == "MW/yr") %>%
select(technology, phase, quantity, energy.carrier,
energy.requirements = value, unit.numerator, unit.denominator),
by = 'technology'
) %>%
# GJ/MWa * GW * 1000 MW/GW = GJ/a
mutate(value = energy.requirements * capacity * 1e3,
phase = "Operation",
unit.denominator = "yr") %>%
unite(unit, unit.numerator, unit.denominator, sep = '/') %>%
select(technology, phase, quantity, energy.carrier, value, unit)
and using electricity production otherwise.
IAM.Electricity.Production %>%
select(technology, electricity.production = value, unit)
energy.requirements %>%
filter(phase == "Operation",
unit.denominator == "kWh") %>%
select(technology, quantity, energy.carrier,
energy.requirements = value, unit.numerator, unit.denominator)
inner_join(
IAM.Electricity.Production %>%
select(technology, electricity.production = value, unit),
energy.requirements %>%
filter(phase == "Operation",
unit.denominator == "kWh") %>%
select(technology, phase, quantity, energy.carrier,
energy.requirements = value, unit.numerator, unit.denominator),
by = 'technology'
) %>%
# GJ/kWh * EJ/a / (3.6e-12 EJ/kWh) = GJ/a
mutate(value = energy.requirements * electricity.production / 3.6e-12,
phase = "Operation",
unit.denominator = "yr") %>%
unite(unit, unit.numerator, unit.denominator, sep = '/') %>%
select(technology, phase, quantity, energy.carrier, value, unit)
The calculation of environmental impacts is analogous to that of energy requirements, but uses different coefficients.
Environmental impacts from construction (again including those of the end-of-life) are calculated by joining the the tables of capacity additions and the LCA coefficients:
IAM.Capacity %>%
filter(phase == "Capacity Additions") %>%
select(technology, capacity.additions = value, unit)
environmental.impacts %>%
filter(phase %in% c("Construction", "End-of-life")) %>%
group_by(scenario, region, technology, technology.variant, impact,
unit.numerator, unit.denominator, period) %>%
summarise(environmental.impacts = sum(value)) %>%
ungroup() %>%
unite(unit, unit.numerator, unit.denominator, sep = '/') %>%
select(technology, impact, environmental.impacts, unit)
inner_join(
IAM.Capacity %>%
filter(phase == "Capacity Additions") %>%
select(technology, capacity.additions = value, unit),
environmental.impacts %>%
filter(phase %in% c("Construction", "End-of-life")) %>%
group_by(scenario, region, technology, technology.variant, impact,
unit.numerator, unit.denominator, period) %>%
summarise(environmental.impacts = sum(value)) %>%
ungroup() %>%
select(technology, impact, environmental.impacts, unit.numerator,
unit.denominator),
by = 'technology'
) %>%
# x/MW * GW/a * 1000 MW/GW = x/a
mutate(value = environmental.impacts * capacity.additions * 1e3,
phase = "Construction",
unit.denominator = "yr") %>%
unite(unit, unit.numerator, unit.denominator, sep = '/') %>%
select(technology, phase, impact, value, unit)
Like energy requirements, the environmental impacts of the operation phase are calculated from LCA coefficients and data on either capacity additions
IAM.Capacity %>%
filter(phase == "Capacity") %>%
select(technology, capacity = value, unit)
environmental.impacts %>%
filter(phase == "Operation",
unit.denominator == "MW/yr") %>%
unite(unit, unit.numerator, unit.denominator, sep = '/') %>%
select(technology, impact, environmental.impacts = value, unit)
inner_join(
IAM.Capacity %>%
filter(phase == "Capacity") %>%
select(technology, capacity = value, unit),
environmental.impacts %>%
filter(phase == "Operation",
unit.denominator == "MW/yr") %>%
select(technology, impact, environmental.impacts = value,
unit.numerator, unit.denominator),
by = 'technology'
) %>%
# x/MWa * GW * 1000 MW/GW = x/a
mutate(value = environmental.impacts * capacity * 1e3,
phase = "Operation",
unit.denominator = "yr") %>%
unite(unit, unit.numerator, unit.denominator, sep = '/') %>%
select(technology, phase, impact, value, unit)
or electricity production, depending on the technology
IAM.Electricity.Production %>%
select(technology, electricity.production = value, unit)
environmental.impacts %>%
filter(phase == "Operation",
unit.denominator == "kWh") %>%
unite(unit, unit.numerator, unit.denominator, sep = '/') %>%
select(technology, impact, environmental.impacts = value, unit)
inner_join(
IAM.Electricity.Production %>%
select(technology, electricity.production = value, unit),
environmental.impacts %>%
filter(phase == "Operation",
unit.denominator == "kWh") %>%
select(technology, impact, environmental.impacts = value,
unit.numerator, unit.denominator),
by = 'technology'
) %>%
# x/kWh * EJ/a / (3.6e-12 EJ/kWh) = x/a
mutate(value = environmental.impacts * electricity.production / 3.6e-12,
phase = "Operation",
unit.denominator = "yr") %>%
unite(unit, unit.numerator, unit.denominator, sep = '/') %>%
select(technology, phase, impact, value, unit)
Emissions from land use and land-use change are calculated separately in the same manner, but based on the coefficients in MAgPIE.luluc.emissions
from the MAgPIE model.
Results from the calculations are simply concatenated and written to .csv
files in the same format as the LCA inputs.
Three files are written: one for both energy requirements and environmental impacts, but only for the default technology variant.
rbind(
rbind(
IAM.energy.requirements.Construction,
IAM.energy.requirements.Operation
) %>%
filter(technology.variant == "mix") %>%
select(-technology.variant) %>%
unite(variable, phase, quantity, energy.carrier, technology, sep = "|"),
rbind(
IAM.environmental.impacts.Construction,
IAM.environmentla.impacts.Operation
) %>%
filter(technology.variant == "mix") %>%
select(-technology.variant) %>%
unite(variable, phase, impact, technology, sep = "|"),
IAM.LULUC.emissions %>%
filter(technology.variant == "mix") %>%
mutate(variable = paste("Emissions", emissions, "LULUC", technology,
sep = "|")) %>%
select(model, scenario, region, variable, unit.numerator,
unit.denominator, period, value)
) %>%
unite(unit, unit.numerator, unit.denominator, sep = "/") %>%
spread(period, value) %>%
write.csv(paste0("./output/", output_file), row.names = FALSE, na = "")
And two files for all technology variants, with energy requirements
rbind(
IAM.energy.requirements.Construction,
IAM.energy.requirements.Operation
) %>%
# GJ/a * 1e-9 EJ/GJ = EJ/a
mutate(value = value * 1e-9,
unit.numerator = "EJ") %>%
unite(unit, unit.numerator, unit.denominator, sep = "/") %>%
spread(period, value) %>%
write.csv(sub("(^.*)(\\.[^\\.]+$)", "./output/\\1_energy\\2", output_file),
row.names = FALSE, na = "")
and environmental impacts separated.
rbind(
IAM.environmental.impacts.Construction,
IAM.environmentla.impacts.Operation,
IAM.LULUC.emissions %>%
mutate(phase = "Operation",
impact = paste("LULUC", emissions, "emissions")) %>%
select(-emissions)
) %>%
unite(unit, unit.numerator, unit.denominator, sep = "/") %>%
spread(period, value) %>%
write.csv(sub("(^.*)(\\.[^\\.]+$)", "./output/\\1_environment\\2",
output_file), row.names = FALSE, na = "")
A simple example plot from the data this tutorial used:
At this step, the IAM and LCA regions are also matched, which is not shown here.↩