Skip to content

Commit

Permalink
Fix issues from v1 rebase
Browse files Browse the repository at this point in the history
Update fuel split calculations in ecm_prep to correctly reflect changes to account for dual fuel measures (commit 130c2d1). Remove superfluous updating of efficient-captured fuel splits data in ecm_prep, which effectively repeated those calculations multiple times. Reapply exogenous heating rates to secondary heating as well in ecm_prep. In run, reintroduce stock cost reporting that was erroneously removed, and add the more robust handling of zero/blank fuel split adjustments from commit c8a21e6.
  • Loading branch information
jtlangevin committed Jan 24, 2025
1 parent 4ba3af0 commit 0b6e2ba
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 53 deletions.
49 changes: 13 additions & 36 deletions scout/ecm_prep.py
Original file line number Diff line number Diff line change
Expand Up @@ -4216,8 +4216,8 @@ def fill_mkts(self, msegs, msegs_cpl, convert_data, tsv_data_init, opts,
no_stk_mseg = ""

# Flag whether exogenous HP rates apply to current mseg.
# Assume only heating, water heating, and cooking end uses are
# covered by these exogenous rates (no secondary heating); do
# Assume only heating, secondary heating, water heating, and cooking
# end uses are covered by these exogenous rates; do
# not apply rates to wood stoves; and ensure that these rates
# are only assessed for equipment microsegments (e.g., they do
# not apply to envelope component heating energy msegs); are
Expand All @@ -4230,7 +4230,7 @@ def fill_mkts(self, msegs, msegs_cpl, convert_data, tsv_data_init, opts,
("stove (wood)" not in self.technology["primary"]) and \
(mskeys[-2] is None or "HP" not in mskeys[-2]) and (any([
x in mskeys for x in [
"heating", "water heating", "cooking"]]) or (
"heating", "secondary heating", "water heating", "cooking"]]) or (
self.linked_htcl_tover and
self.linked_htcl_tover_anchor_eu == "heating")):
hp_rate_flag = True
Expand Down Expand Up @@ -12015,12 +12015,13 @@ def add_sectshape_energy(self, cm, sect_shape_init, add_energy,
# Add energy data for current mseg, subtracting out any efficient-
# case energy that remains with fossil fuel (not applicable to
# sector shapes)
((add_energy[s][yr] * (1 - (fs_eff_splt_energy[0][yr] /
fs_eff_splt_energy[1][yr]))
((add_energy[s][yr] * (1 - (
(fs_eff_splt_energy[0][yr] + fs_eff_splt_energy[1][yr]) /
fs_eff_splt_energy[2][yr]))
# Pull in fuel split as needed
if (fs_eff_splt_energy and s == "efficient" and
"electricity" not in cm
and fs_eff_splt_energy[1][yr] != 0)
and fs_eff_splt_energy[2][yr] != 0)
else add_energy[s][yr])
# Only add energy data to sector shapes if data concerns
# electricity mseg or fuel switching from fossil is occurring and
Expand Down Expand Up @@ -13458,7 +13459,8 @@ def find_adj_out_break_cats(
out_cz][out_bldg][out_eu][out_fuel_gain] = {
yr: mseg_out_break_adj[k]["efficient-captured"][
out_cz][out_bldg][out_eu][out_fuel_gain][yr] - (
eff_capt_orig[yr] - eff_capt_adj[yr])
eff_capt_orig[yr] - eff_capt_adj[yr]) * (
1 - fs_eff_splt_var_capt[yr])
for yr in self.handyvars.aeo_years}
# Update efficient captured for envelope portion of pkg. if
# this is being tracked
Expand All @@ -13480,24 +13482,16 @@ def find_adj_out_break_cats(
eff_orig[yr] - eff_adj[yr]) * (
1 - fs_eff_splt_var[yr]))
for yr in self.handyvars.aeo_years}
# Measure-captured efficient energy for switched to fuel
# (if reported)
if eff_capt:
mseg_out_break_adj[k]["efficient-captured"][
out_cz][out_bldg][out_eu][out_fuel_gain] = {
yr: mseg_out_break_adj[k]["efficient-captured"][
out_cz][out_bldg][out_eu][out_fuel_gain][yr] - (
eff_capt_orig[yr] - eff_capt_adj[yr])
for yr in self.handyvars.aeo_years}
# Energy costs
if all([x for x in [tot_base_orig_ecost, tot_eff_orig_ecost,
tot_save_orig_ecost]]):
# Pull the fraction of efficient-case energy cost that remains
# w/ the orig. fuel in each year for the contrib. measure/mseg
fs_eff_splt_cost = {
yr: (fs_eff_splt["cost"][0][yr] /
fs_eff_splt["cost"][1][yr]) if
fs_eff_splt["cost"][1][yr] != 0 else 1
yr: ((fs_eff_splt["cost"][0][yr] +
fs_eff_splt["cost"][1][yr]) /
fs_eff_splt["cost"][2][yr]) if
fs_eff_splt["cost"][2][yr] != 0 else 1
for yr in self.handyvars.aeo_years}

# Energy cost; original fuel
Expand Down Expand Up @@ -13593,15 +13587,6 @@ def find_adj_out_break_cats(
out_cz][out_bldg][out_eu][out_fuel_save][yr] - (
save_orig[yr] - (base_adj[yr] - eff_adj[yr])) for
yr in self.handyvars.aeo_years}
# Measure-captured efficient energy (if reported)
if eff_capt:
# Remove adjusted efficient
mseg_out_break_adj[k]["efficient-captured"][
out_cz][out_bldg][out_eu][out_fuel_save] = {
yr: mseg_out_break_adj[k]["efficient-captured"][
out_cz][out_bldg][out_eu][out_fuel_save][yr] - (
eff_capt_orig[yr] - eff_capt_adj[yr]) for
yr in self.handyvars.aeo_years}

# Energy costs
if all([x for x in [tot_base_orig_ecost, tot_eff_orig_ecost,
Expand Down Expand Up @@ -13671,14 +13656,6 @@ def find_adj_out_break_cats(
out_cz][out_bldg][out_eu][yr] - (
save_orig[yr] - (base_adj[yr] - eff_adj[yr])) for
yr in self.handyvars.aeo_years}
# Measure-captured efficient energy (if reported)
if eff_capt:
mseg_out_break_adj[k][
"efficient-captured"][out_cz][out_bldg][out_eu] = {
yr: mseg_out_break_adj[k]["efficient-captured"][
out_cz][out_bldg][out_eu][yr] - (
eff_capt_orig[yr] - eff_capt_adj[yr]) for
yr in self.handyvars.aeo_years}

# Energy costs
if all([x for x in [tot_base_orig_ecost, tot_eff_orig_ecost,
Expand Down
141 changes: 124 additions & 17 deletions scout/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -2640,16 +2640,26 @@ def htcl_adj(self, measures_htcl_adj, adopt_scheme, htcl_adj_data):
"total"][var_sub][yr]) * (
1 - adj_frac_t) * fs_eff_splt_var
else:
# Handle efficient-captured energy case for
# fuel switching, where no base fuel data will
# be reported (go to next variable in loop)
# Handle case where no base fuel data is reported, which is
# conceivable for fuel switching (go to next variable in loop)
try:
adj_out_break[
"base fuel"][var][var_sub][yr] = \
adj_out_break["base fuel"][var][
var_sub][yr] - (
adj[var]["total"][var_sub][yr]) * (
1 - adj_frac_t) * fs_eff_splt_var
# Ensure baseline result is not already zero before
# adjusting; if zero, no further adjustment required
if (not isinstance(
adj_out_break["base fuel"][var][var_sub][yr], numpy.ndarray)
and adj_out_break["base fuel"][var][var_sub][yr] != 0) or (
isinstance(
adj_out_break["base fuel"][var][var_sub][yr],
numpy.ndarray) and all(adj_out_break[
"base fuel"][var][var_sub][yr]) != 0):
adj_out_break[
"base fuel"][var][var_sub][yr] = \
adj_out_break["base fuel"][var][
var_sub][yr] - (
adj[var]["total"][var_sub][yr]) * (
1 - adj_frac_t) * fs_eff_splt_var
else:
continue
except KeyError:
continue

Expand Down Expand Up @@ -3862,15 +3872,23 @@ def compete_adj(
adj_key = "measure"
else:
adj_key = var_sub
# Handle efficient-captured energy case for fuel switching,
# where no base fuel data will be reported (skip to next
# variable)
# Handle case where no base fuel data is reported, which is conceivable
# for fuel switching (go to next variable in loop)
try:
adj_out_break["base fuel"][var][var_sub][yr] = \
adj_out_break["base fuel"][var][
var_sub][yr] - (
adj[var]["total"][adj_key][yr]) * (
1 - adj_t) * fs_eff_splt_var
# Ensure baseline result is not already zero before adjusting; if zero, no
# further adjustment required
if (not isinstance(
adj_out_break["base fuel"][var][var_sub][yr], numpy.ndarray)
and adj_out_break["base fuel"][var][var_sub][yr] != 0) or (
isinstance(adj_out_break["base fuel"][var][var_sub][yr], numpy.ndarray)
and all(adj_out_break["base fuel"][var][var_sub][yr]) != 0):
adj_out_break["base fuel"][var][var_sub][yr] = \
adj_out_break["base fuel"][var][
var_sub][yr] - (
adj[var]["total"][adj_key][yr]) * (
1 - adj_t) * fs_eff_splt_var
else:
continue
except KeyError:
continue

Expand Down Expand Up @@ -4995,6 +5013,95 @@ def finalize_outputs(
# the dict with these is calculated above
self.output_ecms[m.name]["Markets and Savings (by Category)"][
adopt_scheme]["Stock Penetration (%)"] = frac_mkt_stk
# If a user desires stock data as an output, calculate and report
# these data for the baseline and measure cases
if self.opts.report_stk is True:
# Set baseline and measure stock keys, including units that
# are calculated above
base_stk_uc_key, base_stk_c_key, meas_stk_key = [
x + stk_units for x in [
"Baseline Stock (Uncompeted)",
"Baseline Stock (Competed)",
"Measure Stock (Competed)"]]
# Report baseline stock and stock cost figures (all baseline
# stock/stock cost that the measure could affect/capture);
# report both uncompeted/competed versions
stk_base_uc = {yr: m.markets[adopt_scheme][
"uncompeted"]["master_mseg"]["stock"][
"total"]["all"][yr] for yr in focus_yrs}
stk_base_c = {
yr: mkts["stock"]["total"]["all"][yr] for yr in focus_yrs}
stk_cost_base = {yr: mkts["cost"]["stock"]["total"][
"baseline"][yr] for yr in focus_yrs}
self.output_ecms[m.name]["Markets and Savings (Overall)"][
adopt_scheme][base_stk_uc_key] = stk_base_uc
self.output_ecms[m.name]["Markets and Savings (Overall)"][
adopt_scheme][base_stk_c_key] = stk_base_c
# Report measure stock and stock cost figures
stk_meas, stk_cost_meas = [{yr: mkts["stock"]["total"][
"measure"][yr] for yr in focus_yrs},
{yr: mkts["cost"]["stock"]["total"][
"efficient"][yr] for yr in focus_yrs}]
# Calculate average and low/high measure stock and stock
# cost figures
stk_meas_avg, stk_cost_meas_avg = [{
k: numpy.mean(v) for k, v in sv.items()} for sv in [
stk_meas, stk_cost_meas]]
stk_meas_low, stk_cost_meas_low = [{
k: numpy.percentile(v, 5) for k, v in sv.items()} for sv
in [stk_meas, stk_cost_meas]]
stk_meas_high, stk_cost_meas_high = [{
k: numpy.percentile(v, 95) for k, v in stk_meas.items()}
for sv in [stk_meas, stk_cost_meas]]
# Set the average measure stock output
self.output_ecms[m.name]["Markets and Savings (Overall)"][
adopt_scheme][meas_stk_key] = stk_meas_avg
# Set the average measure stock cost output
self.output_ecms[m.name]["Markets and Savings (Overall)"][
adopt_scheme][stk_cost_key_tot] = stk_cost_meas_avg
# Set the average measure incremental stock cost output
self.output_ecms[m.name]["Markets and Savings (Overall)"][
adopt_scheme][stk_cost_key_inc] = {
yr: (stk_cost_meas_avg[yr] - stk_cost_base[yr])
for yr in focus_yrs}
# Update stock cost data across all ECMs with data for
# current ECM
for yr in focus_yrs:
# Add to total stock cost data (first element of list)
stk_cost_all_ecms[0][yr] += stk_cost_meas_avg[yr]
# Add to inc. stock cost data (second element of list)
stk_cost_all_ecms[1][yr] += (
stk_cost_meas_avg[yr] - stk_cost_base[yr])
# Set low/high measure stock outputs (as applicable)
if stk_meas_avg != stk_meas_low:
meas_stk_key_low, stk_cost_key_tot_low, \
stk_cost_key_inc_low = [x + " (low)" for x in [
meas_stk_key, stk_cost_key_tot, stk_cost_key_inc]]
meas_stk_key_high, stk_cost_key_tot_high, \
stk_cost_key_inc_high = [x + " (high)" for x in [
meas_stk_key, stk_cost_key_tot, stk_cost_key_inc]]
self.output_ecms[m.name]["Markets and Savings (Overall)"][
adopt_scheme][meas_stk_key_low] = stk_meas_low
self.output_ecms[m.name]["Markets and Savings (Overall)"][
adopt_scheme][meas_stk_key_high] = stk_meas_high
# Set the low measure stock cost output
self.output_ecms[m.name]["Markets and Savings (Overall)"][
adopt_scheme][stk_cost_key_tot_low] = \
stk_meas_low
# Set the low measure incremental stock cost output
self.output_ecms[m.name]["Markets and Savings (Overall)"][
adopt_scheme][stk_cost_key_inc_low] = {
yr: (stk_cost_meas_low[yr] - stk_cost_base[yr])
for yr in focus_yrs}
# Set the high measure stock cost output
self.output_ecms[m.name]["Markets and Savings (Overall)"][
adopt_scheme][stk_cost_key_tot_high] = \
stk_cost_meas_high
# Set the high measure incremental stock cost output
self.output_ecms[m.name]["Markets and Savings (Overall)"][
adopt_scheme][stk_cost_key_inc_high] = {
yr: (stk_cost_meas_high[yr] - stk_meas_high[yr])
for yr in focus_yrs}

# If a user desires output compatible with GCAM format, assess
# impacts of measures on GCAM baselines stock/energy segments.
Expand Down

0 comments on commit 0b6e2ba

Please sign in to comment.