Skip to content

Commit

Permalink
Replace unspecified GHGs & energy inputs with proportional avoided el…
Browse files Browse the repository at this point in the history
…ectricity generation exchanges; addresses #3
  • Loading branch information
a-w-beck committed Sep 2, 2022
1 parent ffcb040 commit 4ef9e19
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 17 deletions.
74 changes: 60 additions & 14 deletions warmer/controls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,80 @@
"""
Functions to enable modifications to WARM data
"""
import pandas as pd

controls_dict = {'electricity': 'control_displaced_electricity_emissions',
'forest': 'remove_forest_carbon_storage',
'fertilizer': 'control_avoided_fertilizer_emissions',
}


def control_displaced_electricity_emissions(df_a, df_b):
# Remove GHGs Unspecified from select processes
b = df_b.query('from_process_name.str.contains("combustion") and '
'to_flow_name == "GHGs, unspecified"', engine='python')
b = b.query('Amount < 0')
df_b = df_b.drop(b.index)

# TODO Add negative electricity output (avoided product) 1.376E+03 kWh/MTCO2E
elec = df_a.query('from_process_name == "Electricity generation, at grid, National"')


e_gen = 'Electricity generation, at grid, National'
ghg_u = 'GHGs, unspecified'

# TODO: derive 1.376E+03 kWh/MTCO2E factor from e_gen elementary flows
# plus factors from new olca_get_results.get_impact_factors fxn
# df_ghgs_to_e = df_b.query('from_process_name == @e_gen and '
# 'Amount != 0')

# For combustion processes w/ a "GHGs, unspecified" output flow and no
# elec. output (avoided product), substitute the former for the latter
# NOTE: all elec. gen. flows are given as inputs w/i the olca mtx exports
df_b_e = df_b.query('from_process_name.str.contains("combustion") and '
'to_flow_name == @ghg_u and '
# 'to_flow_name == "GHGs, unspecified"'
# 'Amount < 0'
'Amount != 0')
prcs_ghg_u = set(df_b_e['from_process_ID'])

df_a_e = df_a.query('from_process_name == @e_gen and '
'Amount != 0')
prcs_e_gen = set(df_a_e['to_process_ID'])

df_target = df_a.query('to_process_ID in @prcs_ghg_u and '
'to_process_ID not in @prcs_e_gen and '
'Amount != 0')
prcs_target = set(df_target['to_process_ID'])

# Construct new e_gen exchanges for target processes & concat into df_a
# Must invert sign when converting output flow to avoided input
# TODO: clarify sign handling here and in olca_warm_matrix_io
flows_e = dict(zip(df_b_e['from_process_ID'],
df_b_e['Amount']*1376*-1))

df_elec_to = (df_a.query('to_process_ID in @prcs_target and '
'Amount != 0')
.filter(regex='^to_')
.drop_duplicates()
.reset_index(drop=True))
df_elec_from = (df_a.query('from_process_name == @e_gen and '
'Amount != 0')
.filter(regex='^from_')
.drop_duplicates())
df_elec_from = (pd.concat([df_elec_from]*len(df_elec_to))
.reset_index(drop=True))

df_elec = pd.concat([df_elec_from, df_elec_to], axis='columns')
df_elec['Amount'] = df_elec['to_process_ID'].map(flows_e)
df_a = pd.concat([df_a, df_elec])

# Remove "GHGs, unspecified" and "Energy, unspecified" (avoided consumption)
# from target processes
unspec = set([ghg_u, 'Energy, unspecified'])
df_b = df_b.query('not (from_process_ID in @prcs_ghg_u and '
'to_flow_name in @unspec)')
return df_a, df_b

def remove_forest_carbon_storage(df_a, df_b):
# Remove Carbon/resource/biotic
b = df_b.query('to_flow_name == "Carbon" and '
'to_flow_category.str.contains("resource/biotic")', engine='python')
b = b.query('Amount < 0')
df_b = df_b.drop(b.index)

return df_a, df_b

def control_avoided_fertilizer_emissions(df_a, df_b):
# Remove carbon dioxide from Anaerobic digestion
b = df_b.query('to_flow_name == "Carbon dioxide" and '
Expand All @@ -39,7 +85,7 @@ def control_avoided_fertilizer_emissions(df_a, df_b):
engine='python')
b = b.query('Amount < 0')
df_b = df_b.drop(b.index)

# TODO Add negative fertilizer output as avoided product

return df_a, df_b
10 changes: 7 additions & 3 deletions warmer/olca_warm_matrix_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ def format_tables(df, opt, opt_map):
}
# Drop all 0 exchanges prior to setting diagonal to 0
df = df.query('Amount != 0').reset_index(drop=True)

# Find and set mtx_a diagonal exchanges to 0, then invert all signs
df['Amount'] = -1 * np.where(
((df['to_process_ID'] == df['from_process_ID'].str.rstrip('/US')) &
Expand Down Expand Up @@ -399,7 +399,7 @@ def get_exchanges(opt_fmt='tables', opt_mixer='pop', opt_map='all',
:param opt_map: str, {'all','fedefl','useeio'}
:param query_fg: bool, True calls query_fg_processes
:param df_subset: pd.DataFrame, see query_fg_processes
:param controls: list
:param controls: list, subset of warmer.controls.controls_dict
"""
if opt_fmt not in {'tables', 'matrices'}:
print(f'"{opt_fmt}" not a valid format option')
Expand All @@ -419,7 +419,8 @@ def get_exchanges(opt_fmt='tables', opt_mixer='pop', opt_map='all',

df_a, df_b = map(melt_mtx, [mtx_a, mtx_b], ['a', 'b'])
df_a, df_b = label_exch_dfs(df_a, df_b, idx_a, idx_b)
df_a, df_b = query_fg_processes(df_a, df_b)

controls = ['electricity']

# Insert controls before mapping
if not controls:
Expand All @@ -431,6 +432,9 @@ def get_exchanges(opt_fmt='tables', opt_mixer='pop', opt_map='all',
else:
print(f'control {c} does not exist.')


# df_a, df_b = map(lambda x: x.query('Amount != 0'), (df_a, df_b))
# return df_a, df_b
if opt_map in {'all', 'useeio'}:
df_a = map_useeio_processes(df_a)
if opt_map in {'all', 'fedefl'}:
Expand Down

0 comments on commit 4ef9e19

Please sign in to comment.