Energy Efficiency Gap Simulation

This exercise walks you through a simulation of the energy efficiency gap model from Allcott & Greenstone (2012). You will simulate consumer choices over two types of air conditioners (inefficient and efficient) under different assumptions about information and attention to energy costs. You will then analyze the social and private costs associated with these choices, and evaluate potential policy interventions. The goal is to give you a numerical, more hands on understanding of the model discussed in the lecture.

Software Implementation Note

This problem set includes pseudo-code for R, Stata, and Excel. Only the R implementation has been fully tested. The Stata and Excel instructions are provided as guidance, but you should verify they work correctly for your specific versions.

Background

You are analyzing the market for room air conditioners using the energy efficiency framework from Allcott & Greenstone. There are two types of air conditioners available:

  • Inefficient model (I): Price = $300, energy efficiency \(e_I = 1.0\) kWh per unit cooling
  • Efficient model (E): Price = $400, energy efficiency \(e_E = 0.5\) kWh per unit cooling

Consumers are heterogeneous in three dimensions:

  1. Cooling demand (\(m\)): Uniformly distributed between 1,000 and 3,000 hours of use per year
  2. Electricity price (\(p\)): Uniformly distributed between $0.05 and $0.25 per kWh
  3. Discount rate (\(r\)): Uniformly distributed between 3% and 23%

Assume air conditioners last for 10 years and all energy costs occur as a lump sum one year from now (for simplicity).

The total cost for a consumer purchasing air conditioner type \(j\) is:

\[TC_j = c_j + \frac{e_j \cdot p \cdot m}{1 + r}\]

where \(c_j\) is the upfront price and the second term is the present discounted value of lifetime energy costs.


Part 1: Baseline Model with Full Information (\(\gamma = 1\))

Setup

Generate a dataset of \(N = 1{,}000\) consumers with random draws for \(m\), \(p\), and \(r\).

Task

For each consumer, calculate:

  • Total cost of inefficient model: \(TC_I = c_I + \frac{e_I \times p \times m}{1 + r}\)
  • Total cost of efficient model: \(TC_E = c_E + \frac{e_E \times p \times m}{1 + r}\)

A rational, fully-informed consumer chooses E if \(TC_E < TC_I\).

Calculate:

  1. The share of consumers who purchase the efficient model (market share of E)
  2. Plot a histogram showing the distribution of total cost savings (\(TC_I - TC_E\)) for all consumers

Part 2: Adding Externalities (Social Optimum)

Setup

Electricity generation creates pollution externalities. Add a social cost of \(\phi = \$0.10\) per kWh.

Task

Recalculate total costs using the social price \(p_{social} = p + \phi\):

  • Social \(TC_I = c_I + \frac{e_I \times p_{social} \times m}{1 + r}\)
  • Social \(TC_E = c_E + \frac{e_E \times p_{social} \times m}{1 + r}\)

Calculate:

  1. The socially optimal share of E (share of consumers for whom Social \(TC_E <\) Social \(TC_I\))
  2. Compare to Part 1—what is the “social efficiency gap”?

Part 3: Inattention to Energy Costs (\(\gamma = 0.5\))

Setup

Consumers now underweight future energy savings. They perceive energy savings as only \(\gamma = 0.5\) times the actual value.

Task

Consumer perceived total costs are:

  • Perceived \(TC_I = c_I + \gamma \times \frac{e_I \times p \times m}{1 + r}\)
  • Perceived \(TC_E = c_E + \gamma \times \frac{e_E \times p \times m}{1 + r}\)

Consumers choose E if Perceived \(TC_E <\) Perceived \(TC_I\).

Calculate:

  1. The market share of E under inattention
  2. How does this compare to Parts 1 and 2?

Part 4: Cost Analysis

For the scenario in Part 3 (\(\gamma = 0.5\)), calculate three cost measures:

A. Total Social Costs (TSC)

For each consumer, calculate the actual social cost (using \(p_{social}\)) of their chosen product. Sum across all consumers. This represents the true cost to society.

B. Total Private Costs (TPC)

For each consumer, calculate the actual private cost (using \(p\), not \(p_{social}\)) of their chosen product. This is what consumers actually pay. Sum across all consumers.

C. Total Perceived Costs (TPC)

For each consumer, calculate the perceived cost (using \(\gamma = 0.5\)) of their chosen product. This represents costs from their decision-making perspective. Sum across all consumers.

Calculate:

  1. Compare TSC, TPC, and TDC under the inattention scenario
  2. How much additional social cost results from inattention? (Compare to optimal outcomes from Part 2)
  3. How much would consumers save if they chose optimally from their own private perspective? (Compare TPC under \(\gamma = 0.5\) to optimal TPC from Part 1)

Part 5: Policy Analysis

Consider two policies:

  1. Information campaign: Increases \(\gamma\) from 0.5 to 0.75 (costs $0)
  2. Rebate: Reduces \(c_E\) by $100 (costs $100 per efficient AC sold)

Calculate:

For each policy:

  1. New market share of E
  2. Change in total social costs
  3. Government cost (for rebate policy)
  4. Cost-effectiveness ($/ton CO₂ if 1,000 kWh = 0.5 tons CO₂)

Implementation Guide

Pseudo-Code (General Algorithm)

This pseudo-code outlines the steps to implement the simulation in any programming language. You could paste this into any AI to get language-specific code. I have also pasted R, Stata, and Excel implementations below. Only the R code has been tested.

# Setup
N = 1000
c_I = 300
c_E = 400
e_I = 1.0
e_E = 0.5
phi = 0.10
life = 10

# Simulate consumer heterogeneity
FOR i = 1 to N:
    m[i] = UNIFORM(1000, 3000)  # hours of use
    p[i] = UNIFORM(0.05, 0.25)  # electricity price
    r[i] = UNIFORM(0.03, 0.23)  # discount rate

# Part 1: Full information (gamma = 1)
FOR i = 1 to N:
    TC_I[i] = c_I + (e_I * p[i] * m[i]) / (1 + r[i])
    TC_E[i] = c_E + (e_E * p[i] * m[i]) / (1 + r[i])
    choice_full[i] = IF TC_E[i] < TC_I[i] THEN "E" ELSE "I"

share_E_full = COUNT(choice_full == "E") / N

# Part 2: Social optimum
FOR i = 1 to N:
    p_social[i] = p[i] + phi
    TC_I_social[i] = c_I + (e_I * p_social[i] * m[i]) / (1 + r[i])
    TC_E_social[i] = c_E + (e_E * p_social[i] * m[i]) / (1 + r[i])
    choice_social[i] = IF TC_E_social[i] < TC_I_social[i] THEN "E" ELSE "I"

share_E_social = COUNT(choice_social == "E") / N

# Part 3: Inattention (gamma = 0.5)
gamma = 0.5
FOR i = 1 to N:
    TC_I_perceived[i] = c_I + gamma * (e_I * p[i] * m[i]) / (1 + r[i])
    TC_E_perceived[i] = c_E + gamma * (e_E * p[i] * m[i]) / (1 + r[i])
    choice_inattention[i] = IF TC_E_perceived[i] < TC_I_perceived[i] THEN "E" ELSE "I"

share_E_inattention = COUNT(choice_inattention == "E") / N

# Part 4: Cost calculations
FOR i = 1 to N:
    IF choice_inattention[i] == "E":
        actual_social_cost[i] = TC_E_social[i]
        actual_private_cost[i] = TC_E[i]
        perceived_cost[i] = TC_E_perceived[i]
    ELSE:
        actual_social_cost[i] = TC_I_social[i]
        actual_private_cost[i] = TC_I[i]
        perceived_cost[i] = TC_I_perceived[i]

TSC_inattention = SUM(actual_social_cost)
TPC_inattention = SUM(actual_private_cost)
TDC_inattention = SUM(perceived_cost)

# Optimal costs for comparison
TSC_optimal = SUM(MIN(TC_E_social, TC_I_social) for each consumer)
TPC_optimal = SUM(MIN(TC_E, TC_I) for each consumer)

additional_social_cost = TSC_inattention - TSC_optimal
additional_private_cost = TPC_inattention - TPC_optimal

R Implementation

# Load required libraries
library(tidyverse)
library(scales)

set.seed(42)

# Parameters
N <- 1000
c_I <- 300
c_E <- 400
e_I <- 1.0
e_E <- 0.5
phi <- 0.10
life <- 10

# Simulate consumer heterogeneity
consumers <- tibble(
  id = 1:N,
  m = runif(N, 1000, 3000),
  p = runif(N, 0.05, 0.25),
  r = runif(N, 0.03, 0.23)
)

# Part 1: Full Information
consumers <- consumers %>%
  mutate(
    TC_I_full = c_I + (e_I * p * m) / (1 + r),
    TC_E_full = c_E + (e_E * p * m) / (1 + r),
    choice_full = ifelse(TC_E_full < TC_I_full, "E", "I"),
    savings_full = TC_I_full - TC_E_full
  )

share_E_full <- mean(consumers$choice_full == "E")
cat(sprintf("Part 1 - Market share of E: %.1f%%\n", share_E_full * 100))

# Histogram
ggplot(consumers, aes(x = savings_full)) +
  geom_histogram(bins = 50, fill = "steelblue", alpha = 0.7) +
  geom_vline(xintercept = 0, color = "red", linetype = "dashed") +
  labs(title = "Distribution of Cost Savings from Efficient AC",
       x = "Cost Savings ($)", y = "Count") +
  theme_minimal()

# Part 2: Social Optimum
consumers <- consumers %>%
  mutate(
    p_social = p + phi,
    TC_I_social = c_I + (e_I * p_social * m) / (1 + r),
    TC_E_social = c_E + (e_E * p_social * m) / (1 + r),
    choice_social = ifelse(TC_E_social < TC_I_social, "E", "I")
  )

share_E_social <- mean(consumers$choice_social == "E")
cat(sprintf("Part 2 - Socially optimal share: %.1f%%\n", share_E_social * 100))

# Part 3: Inattention
gamma <- 0.5
consumers <- consumers %>%
  mutate(
    TC_I_perceived = c_I + gamma * (e_I * p * m) / (1 + r),
    TC_E_perceived = c_E + gamma * (e_E * p * m) / (1 + r),
    choice_inattention = ifelse(TC_E_perceived < TC_I_perceived, "E", "I")
  )

share_E_inattention <- mean(consumers$choice_inattention == "E")
cat(sprintf("Part 3 - Market share with inattention: %.1f%%\n", 
            share_E_inattention * 100))

# Part 4: Cost Analysis
consumers <- consumers %>%
  mutate(
    actual_social_cost = ifelse(choice_inattention == "E", 
                                TC_E_social, TC_I_social),
    actual_private_cost = ifelse(choice_inattention == "E",
                                 TC_E_full, TC_I_full),
    optimal_social_cost = pmin(TC_E_social, TC_I_social),
    optimal_private_cost = pmin(TC_E_full, TC_I_full)
  )

TSC_inattention <- sum(consumers$actual_social_cost)
TPC_inattention <- sum(consumers$actual_private_cost)
TSC_optimal <- sum(consumers$optimal_social_cost)
TPC_optimal <- sum(consumers$optimal_private_cost)

cat(sprintf("Part 4 - Total Social Costs (inattention): $%.0f\n", TSC_inattention))
cat(sprintf("Part 4 - Total Social Costs (optimal): $%.0f\n", TSC_optimal))
cat(sprintf("Part 4 - Additional social cost: $%.0f\n", 
            TSC_inattention - TSC_optimal))

# Part 5: Policy Analysis
# Policy 1: Information campaign
gamma_policy1 <- 0.75
consumers <- consumers %>%
  mutate(
    TC_I_policy1 = c_I + gamma_policy1 * (e_I * p * m) / (1 + r),
    TC_E_policy1 = c_E + gamma_policy1 * (e_E * p * m) / (1 + r),
    choice_policy1 = ifelse(TC_E_policy1 < TC_I_policy1, "E", "I")
  )

share_E_policy1 <- mean(consumers$choice_policy1 == "E")
cat(sprintf("Part 5 - Info campaign share: %.1f%%\n", share_E_policy1 * 100))

# Policy 2: Rebate
c_E_policy2 <- c_E - 100
consumers <- consumers %>%
  mutate(
    TC_E_policy2 = c_E_policy2 + gamma * (e_E * p * m) / (1 + r),
    choice_policy2 = ifelse(TC_E_policy2 < TC_I_perceived, "E", "I")
  )

share_E_policy2 <- mean(consumers$choice_policy2 == "E")
gov_cost <- 100 * sum(consumers$choice_policy2 == "E")
cat(sprintf("Part 5 - Rebate share: %.1f%%\n", share_E_policy2 * 100))
cat(sprintf("Part 5 - Government cost: $%.0f\n", gov_cost))

Stata Implementation

clear all
set seed 42

* Parameters
local N = 1000
local c_I = 300
local c_E = 400
local e_I = 1.0
local e_E = 0.5
local phi = 0.10
local life = 10

* Create dataset
set obs `N'
gen id = _n

* Simulate consumer heterogeneity
gen m = 1000 + 2000 * runiform()          // Uniform[1000, 3000]
gen p = 0.05 + 0.20 * runiform()          // Uniform[0.05, 0.25]
gen r = 0.03 + 0.20 * runiform()          // Uniform[0.03, 0.23]

* Part 1: Full Information
gen TC_I_full = `c_I' + (`e_I' * p * m) / (1 + r)
gen TC_E_full = `c_E' + (`e_E' * p * m) / (1 + r)
gen choice_full = (TC_E_full < TC_I_full)
gen savings_full = TC_I_full - TC_E_full

* Market share
sum choice_full
local share_E_full = r(mean)
display "Part 1 - Market share of E: " %3.1f `share_E_full'*100 "%"

* Histogram
histogram savings_full, width(50) frequency ///
    title("Distribution of Cost Savings") ///
    xtitle("Cost Savings ($)") ytitle("Count") ///
    scheme(s2color)

* Part 2: Social Optimum
gen p_social = p + `phi'
gen TC_I_social = `c_I' + (`e_I' * p_social * m) / (1 + r)
gen TC_E_social = `c_E' + (`e_E' * p_social * m) / (1 + r)
gen choice_social = (TC_E_social < TC_I_social)

sum choice_social
local share_E_social = r(mean)
display "Part 2 - Socially optimal share: " %3.1f `share_E_social'*100 "%"

* Part 3: Inattention
local gamma = 0.5
gen TC_I_perceived = `c_I' + `gamma' * (`e_I' * p * m) / (1 + r)
gen TC_E_perceived = `c_E' + `gamma' * (`e_E' * p * m) / (1 + r)
gen choice_inattention = (TC_E_perceived < TC_I_perceived)

sum choice_inattention
local share_E_inattention = r(mean)
display "Part 3 - Market share with inattention: " ///
    %3.1f `share_E_inattention'*100 "%"

* Part 4: Cost Analysis
gen actual_social_cost = cond(choice_inattention, TC_E_social, TC_I_social)
gen actual_private_cost = cond(choice_inattention, TC_E_full, TC_I_full)
gen optimal_social_cost = min(TC_E_social, TC_I_social)
gen optimal_private_cost = min(TC_E_full, TC_I_full)

sum actual_social_cost
local TSC_inattention = r(sum)
sum optimal_social_cost
local TSC_optimal = r(sum)
local additional_social_cost = `TSC_inattention' - `TSC_optimal'

display "Part 4 - Total Social Costs (inattention): $" %10.0fc `TSC_inattention'
display "Part 4 - Total Social Costs (optimal): $" %10.0fc `TSC_optimal'
display "Part 4 - Additional social cost: $" %10.0fc `additional_social_cost'

* Part 5: Policy Analysis

* Policy 1: Information campaign
local gamma_policy1 = 0.75
gen TC_I_policy1 = `c_I' + `gamma_policy1' * (`e_I' * p * m) / (1 + r)
gen TC_E_policy1 = `c_E' + `gamma_policy1' * (`e_E' * p * m) / (1 + r)
gen choice_policy1 = (TC_E_policy1 < TC_I_policy1)

sum choice_policy1
local share_E_policy1 = r(mean)
display "Part 5 - Info campaign share: " %3.1f `share_E_policy1'*100 "%"

* Policy 2: Rebate
local c_E_policy2 = `c_E' - 100
gen TC_E_policy2 = `c_E_policy2' + `gamma' * (`e_E' * p * m) / (1 + r)
gen choice_policy2 = (TC_E_policy2 < TC_I_perceived)

sum choice_policy2
local share_E_policy2 = r(mean)
local gov_cost = 100 * r(sum)

display "Part 5 - Rebate share: " %3.1f `share_E_policy2'*100 "%"
display "Part 5 - Government cost: $" %10.0fc `gov_cost'

Excel Implementation

Step 1: Set up parameters (in a separate sheet called “Parameters”)

Parameter Value
N 1000
c_I 300
c_E 400
e_I 1.0
e_E 0.5
phi 0.10
gamma_base 0.5
gamma_policy1 0.75

Step 2: Create consumer data (Sheet: “Consumers”)

Create columns A-E with headers in row 1:

  • Column A: id (numbers 1 to 1000)
  • Column B: m = =1000+RAND()*2000
  • Column C: p = =0.05+RAND()*0.20
  • Column D: r = =0.03+RAND()*0.20
  • Column E: p_social = =C2+Parameters!$B$7 (drag down)

Step 3: Part 1 - Full Information (Columns F-I)

  • Column F: TC_I_full = =Parameters!$B$2+(Parameters!$B$4*C2*B2)/(1+D2)
  • Column G: TC_E_full = =Parameters!$B$3+(Parameters!$B$5*C2*B2)/(1+D2)
  • Column H: choice_full = =IF(G2<F2,"E","I")
  • Column I: savings_full = =F2-G2

Calculate market share in a separate cell: =COUNTIF(H:H,"E")/1000

Create histogram of Column I (Insert → Chart → Histogram)

Step 4: Part 2 - Social Optimum (Columns J-L)

  • Column J: TC_I_social = =Parameters!$B$2+(Parameters!$B$4*E2*B2)/(1+D2)
  • Column K: TC_E_social = =Parameters!$B$3+(Parameters!$B$5*E2*B2)/(1+D2)
  • Column L: choice_social = =IF(K2<J2,"E","I")

Calculate market share: =COUNTIF(L:L,"E")/1000

Step 5: Part 3 - Inattention (Columns M-O)

  • Column M: TC_I_perceived = =Parameters!$B$2+Parameters!$B$8*(Parameters!$B$4*C2*B2)/(1+D2)
  • Column N: TC_E_perceived = =Parameters!$B$3+Parameters!$B$8*(Parameters!$B$5*C2*B2)/(1+D2)
  • Column O: choice_inattention = =IF(N2<M2,"E","I")

Calculate market share: =COUNTIF(O:O,"E")/1000

Step 6: Part 4 - Cost Analysis (Columns P-S)

  • Column P: actual_social_cost = =IF(O2="E",K2,J2)
  • Column Q: actual_private_cost = =IF(O2="E",G2,F2)
  • Column R: optimal_social_cost = =MIN(J2,K2)
  • Column S: optimal_private_cost = =MIN(F2,G2)

Calculate totals:

  • TSC_inattention: =SUM(P:P)
  • TPC_inattention: =SUM(Q:Q)
  • TSC_optimal: =SUM(R:R)
  • TPC_optimal: =SUM(S:S)
  • Additional social cost: =TSC_inattention - TSC_optimal

Step 7: Part 5 - Policy Analysis (Columns T-W)

Policy 1: Information Campaign

  • Column T: TC_I_policy1 = =Parameters!$B$2+Parameters!$B$9*(Parameters!$B$4*C2*B2)/(1+D2)
  • Column U: TC_E_policy1 = =Parameters!$B$3+Parameters!$B$9*(Parameters!$B$5*C2*B2)/(1+D2)
  • Column V: choice_policy1 = =IF(U2<T2,"E","I")

Calculate market share: =COUNTIF(V:V,"E")/1000

Policy 2: Rebate

  • Column W: TC_E_policy2 = =(Parameters!$B$3-100)+Parameters!$B$8*(Parameters!$B$5*C2*B2)/(1+D2)
  • Column X: choice_policy2 = =IF(W2<M2,"E","I")

Calculate market share: =COUNTIF(X:X,"E")/1000

Calculate government cost: =COUNTIF(X:X,"E")*100

Note: After setting up formulas, select all data cells and press F9 to recalculate with new random draws.


Deliverables

Submit a report (2-3 pages) with:

  1. Table of market shares from Parts 1-3
  2. Histogram of cost savings distribution (Part 1)
  3. Table of cost measures (Part 4) showing TSC, TPC, TDC under inattention vs. optimal
  4. Policy comparison table (Part 5) showing market shares, cost changes, and cost-effectiveness
  5. Brief discussion (1-2 paragraphs each):
    • Why does inattention reduce demand for efficient products?
    • Who bears the costs of consumer inattention?
    • Which policy is more effective? Why?
    • What are the limitations of this simple model?