Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GHG Accounting #391

Merged
merged 5 commits into from
Aug 26, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
454 changes: 454 additions & 0 deletions KC_ghg_tutorial.py

Large diffs are not rendered by default.

100 changes: 82 additions & 18 deletions model/ch4calcs.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""CH4 Calcs module.

Computes reductions in CO2-equivalent emissions.
Computes reductions for methane in individual gas units and CO2-equivalent emissions.
"""

from functools import lru_cache
Expand All @@ -9,6 +9,9 @@

from model.data_handler import DataHandler
from model.decorators import data_func
from model import emissionsfactors



class CH4Calcs(DataHandler):
"""CH4 Calcs module.
Expand All @@ -26,67 +29,128 @@ def __init__(self, ac, soln_net_annual_funits_adopted,
self.soln_pds_direct_ch4_co2_emissions_saved = soln_pds_direct_ch4_co2_emissions_saved



@lru_cache()
@data_func
def ch4_tons_reduced(self):
"""CH4 reduced, in tons.
replace gas_ch4_step = `gas_tons_ch4' * `e'^(-(time_from_present - `n')/12)
SolarPVUtil 'CH4 Calcs'!A10:K56
def ch4_co2eq_tons_reduced(self):
"""CH4 reduced, in tons of CO2eq per year.
"""
if self.ac.ch4_is_co2eq:
result = self.soln_net_annual_funits_adopted * 0
else:
result = self.soln_net_annual_funits_adopted * self.ac.ch4_co2_per_funit
result.loc[:self.ac.report_start_year - 1] = 0.0
result.loc[self.ac.report_end_year + 1:] = 0.0
result.name = "ch4_co2eq_tons_reduced"
return result

@lru_cache()
def ch4_tons_reduced(self):
"""CH4 reduced from the RRS model, in tons CH4 per year.
"""
if self.ac.ch4_is_co2eq:
ef = emissionsfactors.CO2Equiv(self.ac.co2eq_conversion_source)
result = (self.soln_net_annual_funits_adopted * self.ac.ch4_co2_per_funit)/ef.CH4multiplier
else:
result = self.soln_net_annual_funits_adopted * self.ac.ch4_co2_per_funit
result.loc[:self.ac.report_start_year - 1] = 0.0
result.loc[self.ac.report_end_year + 1:] = 0.0
result.name = "ch4_tons_reduced"
return result



@lru_cache()
def avoided_direct_emissions_ch4_land(self):
"""CH4 emissions avoided, in tons
replace gas_ch4_step = `gas_tons_ch4' * `e'^(-(time_from_present - `n')/12)
Improved Rice 'CH4 Calcs'!A12:K58
def avoided_direct_emissions_ch4_co2eq_land(self):
"""CH4 emissions avoided from the land model, in tons of CO2eq per year
"""
result = self.soln_pds_direct_ch4_co2_emissions_saved.copy(deep=True)
result.loc[:self.ac.report_start_year - 1] = 0.0
result.loc[self.ac.report_end_year + 1:] = 0.0
result.name = "avoided_direct_emissions_ch4_co2eq_land"
return result



@lru_cache()
def avoided_direct_emissions_ch4_land(self):
"""CH4 direct emissions avoided, in tons per year
"""
ef = emissionsfactors.CO2Equiv(self.ac.co2eq_conversion_source)
result = self.soln_pds_direct_ch4_co2_emissions_saved.copy(deep=True) / ef.CH4multiplier
result.loc[:self.ac.report_start_year - 1] = 0.0
result.loc[self.ac.report_end_year + 1:] = 0.0
result.name = "avoided_direct_emissions_ch4_land"
return result



@lru_cache()
def ch4_megatons_avoided_or_reduced(self):
"""CH4 emissions avoided or reduced, in megatons per year (units needed for the FaIR model). A key result!
"""
if self.soln_pds_direct_ch4_co2_emissions_saved is not None:
ch4_tons = self.avoided_direct_emissions_ch4_land()
else:
ch4_tons = self.ch4_tons_reduced()
result = ch4_tons * 0.000001
result.name = "ch4_megatons_avoided_or_reduced"
return result



@lru_cache()
def ch4_ppb_calculator(self):
def ch4_ppb_calculator_avoided_or_reduced(self):
"""Parts Per Billion reduction calculator for CH4.

Each yearly reduction in CH4 (in metric tons) is modeled as a discrete avoided pulse.
A Simplified atmospheric lifetime function for CH4 is taken from Myhrvald and Caldeira
(2012). Atmospheric tons of CH4 are converted to parts per billion CH4 based on the
molar mass of CH4 and the moles of atmosphere.

SolarPVUtil 'CH4 Calcs'!A64:AW110
"""
if self.soln_pds_direct_ch4_co2_emissions_saved is not None:
ch4_tons = self.avoided_direct_emissions_ch4_land()
else:
ch4_tons = self.ch4_tons_reduced()

col_years = np.arange(2015, 2061)
index_years = ch4_tons.index.values

deltas = index_years.reshape(-1, 1) - col_years.reshape(1, -1) + 1

vals = np.exp( - deltas / 12) * ch4_tons.loc[col_years, "World"].values.reshape(1, -1)
vals[deltas < 1] = 0 # Overwrite values for negative deltas

total = vals.sum(axis=1).reshape(-1, 1)
ppb = total / (16.04 * 1.8 * 10 ** 5)
ppb_calculator = pd.DataFrame(np.concatenate([ppb, total, vals], axis=1),
columns=["PPB", "Total"] + list(col_years),
index=ch4_tons.index.copy(),
dtype=np.float64
)
ppb_calculator.name = "ch4_ppb_calculator_avoided_or_reduced"
return ppb_calculator



@lru_cache()
def ch4_ppb_calculator(self):
"""Parts Per Billion reduction calculator for CH4 using CO2eq.
This is the original way drawdown was calculating the concentration of methane
in the atmosphere. This way is incorrect since the equation taken from Myhrvald and Caldeira (2012)
assumes metric tons are converted to ppb, NOT CO2eq tons of methane (like it is done here).
"""
if self.soln_pds_direct_ch4_co2_emissions_saved is not None:
ch4_tons = self.avoided_direct_emissions_ch4_co2eq_land()
else:
ch4_tons = self.ch4_co2eq_tons_reduced()
col_years = np.arange(2015, 2061)
index_years = ch4_tons.index.values
deltas = index_years.reshape(-1, 1) - col_years.reshape(1, -1) + 1
vals = np.exp( - deltas / 12) * ch4_tons.loc[col_years, "World"].values.reshape(1, -1)
vals[deltas < 1] = 0 # Overwrite values for negative deltas
total = vals.sum(axis=1).reshape(-1, 1)
ppb = total / (16.04 * 1.8 * 10 ** 5)
ppb_calculator = pd.DataFrame(np.concatenate([ppb, total, vals], axis=1),
columns=["PPB", "Total"] + list(col_years),
index=ch4_tons.index.copy(),
dtype=np.float64
)
ppb_calculator.name = "ch4_ppb_calculator"
ppb_calculator.name = "ch4_ppb_calculator_co2eq"
return ppb_calculator

Loading