Skip to content

Commit

Permalink
Merge branch 'fix-scmdf_to_emissions'
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisroadmap committed Jul 9, 2020
2 parents c95422e + 4046216 commit 639bdd1
Show file tree
Hide file tree
Showing 5 changed files with 441 additions and 77 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ Changelog

master
------

(`#77 <https://github.com/OMS-NetZero/FAIR/pull/77>`_) Fixed ``fair.tools.scmdf.scmdf_to_emissions``

(`#76 <https://github.com/OMS-NetZero/FAIR/pull/76>`_) Added in the GIR carbon cycle as an option and ScmDataFrame reader, required for openscm-runner and iiasa-climate-assessment

(`#69 <https://github.com/OMS-NetZero/FAIR/pull/69>`_) Added in switch to directly specify tropospheric ozone forcing time series and added in AR6 radiative efficiencies, lifetimes and molecular weights
Expand Down
186 changes: 110 additions & 76 deletions fair/tools/scmdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,60 @@

from ..constants import molwt

def scmdf_to_emissions(scmdf, include_cfcs=True, startyear=1765, endyear=2100):
try:
from scmdata import ScmDataFrame
has_scmdata = True
except ImportError:
has_scmdata = False


EMISSIONS_SPECIES_UNITS_CONTEXT = ( # in fair 1.6, order is important
# @chrisroadmap can you check please
('|CO2|MAGICC Fossil and Industrial', 'GtC / yr', None),
('|CO2|MAGICC AFOLU', 'GtC / yr', None),
('|CH4', 'MtCH4 / yr', None),
('|N2O', 'MtN / yr', None),
('|Sulfur', 'MtS / yr', None),
('|CO', 'MtCO / yr', None),
('|VOC', 'MtNMVOC / yr', None),
('|NOx', 'MtN / yr', "NOx_conversions"),
('|BC', 'MtBC / yr', None),
('|OC', 'MtOC / yr', None),
('|NH3', 'MtN / yr', None),
('|CF4', 'ktCF4 / yr', None),
('|C2F6', 'ktC2F6 / yr', None),
('|C6F14', 'ktC6F14 / yr', None),
('|HFC23', 'ktHFC23 / yr', None),
('|HFC32', 'ktHFC32 / yr', None),
('|HFC4310mee', 'ktHFC4310mee / yr', None),
('|HFC125', 'ktHFC125 / yr', None),
('|HFC134a', 'ktHFC134a / yr', None),
('|HFC143a', 'ktHFC143a / yr', None),
('|HFC227ea', 'ktHFC227ea / yr', None),
('|HFC245fa', 'ktHFC245fa / yr', None),
('|SF6', 'ktSF6 / yr', None),
('|CFC11', 'ktCFC11 / yr', None),
('|CFC12', 'ktCFC12 / yr', None),
('|CFC113', 'ktCFC113 / yr', None),
('|CFC114', 'ktCFC114 / yr', None),
('|CFC115', 'ktCFC115 / yr', None),
('|CCl4', 'ktCCl4 / yr', None),
('|CH3CCl3', 'ktCH3CCl3 / yr', None),
('|HCFC22', 'ktHCFC22 / yr', None),
('|HCFC141b', 'ktHCFC141b / yr', None),
('|HCFC142b', 'ktHCFC142b / yr', None),
('|Halon1211', 'ktHalon1211 / yr', None),
('|Halon1202', 'ktHalon1202 / yr', None),
('|Halon1301', 'ktHalon1301 / yr', None),
('|Halon2402', 'ktHalon2402 / yr', None),
('|CH3Br', 'ktCH3Br / yr', None),
('|CH3Cl', 'ktCH3Cl / yr', None),
)


def scmdf_to_emissions(scmdf, include_cfcs=True, startyear=1765, endyear=2100):
"""
Opens a ScmDataFrame and extracts the data. Interpolates linearly
Opens an ScmDataFrame and extracts the data. Interpolates linearly
between non-consecutive years in the SCEN file. Fills in chlorinated gases
from a specified SSP scenario.
Expand All @@ -24,12 +74,12 @@ def scmdf_to_emissions(scmdf, include_cfcs=True, startyear=1765, endyear=2100):
MAGICC files do not come loaded with CFCs (indices 24-39).
- if True, use the values from RCMIP for SSPs (all scenarios are
the same).
- Use False to ignore and create a 24-species emission file.
- Use False to ignore and create a 23-species emission file.
startyear: First year of output file.
endyear: Last year of output file.
Returns:
nt x 40 numpy emissions array
nt x 40 numpy emissions array (nt x 23 if ``include_cfcs`` is ``False``)
"""

# We expect that aeneris and silicone are going to give us a nicely
Expand All @@ -39,88 +89,72 @@ def scmdf_to_emissions(scmdf, include_cfcs=True, startyear=1765, endyear=2100):
# historical.
# This adapter will not be tested on anything else!

n_timepoints = scmdf.shape[1]
n_cols = 40
nt = endyear - startyear + 1

data_out = np.ones((nt, n_cols)) * np.nan
data_out[:,0] = np.arange(startyear, endyear+1)

if not has_scmdata:
raise ImportError("This is not going to work without having scmdata installed")

if not isinstance(scmdf, ScmDataFrame):
raise TypeError("scmdf must be an scmdata.ScmDataFrame instance")

if not include_cfcs:
raise NotImplementedError("include_cfcs equal to False")

if scmdf[["model", "scenario"]].drop_duplicates().shape[0] != 1:
raise AssertionError("Should only have one model-scenario pair")

# fill in 1765 to 2014 from SSP emissions
ssp_df = pd.read_csv(os.path.join(os.path.dirname(__file__), '../SSPs/data/rcmip-emissions-annual-means-4-0-0-ssp-only.csv'))
ssp_df = ScmDataFrame(os.path.join(os.path.dirname(__file__), '../SSPs/data/rcmip-emissions-annual-means-4-0-0-ssp-only.csv'))

years = scmdf.columns
years = scmdf["year"].values
first_scenyear = years[0]
last_scenyear = years[-1]
first_row = int(first_scenyear-startyear)
last_row = int(last_scenyear-startyear)

species = [ # in fair 1.6, order is important
'|CO2|Energy and Industrial Processes',
'|CO2|AFOLU',
'|CH4',
'|N2O',
'|Sulfur',
'|CO',
'|VOC',
'|NOx',
'|BC',
'|OC',
'|NH3',
'|CF4',
'|C2F6',
'|C6F14',
'|HFC23',
'|HFC32',
'|HFC43-10',
'|HFC125',
'|HFC134a',
'|HFC143a',
'|HFC227ea',
'|HFC245ca',
'|SF6',
]

emissions_file_species = species.copy()
emissions_file_species[0] = '|CO2|MAGICC Fossil and Industrial'
emissions_file_species[1] = '|CO2|MAGICC AFOLU'
emissions_file_species[16] = '|HFC4310mee'
emissions_file_species[21] = '|HFC245fa'
emissions_file_species.extend([
'|CFC11',
'|CFC12',
'|CFC113',
'|CFC114',
'|CFC115',
'|CCl4',
'|CH3CCl3',
'|HCFC22',
'|HCFC141b',
'|HCFC142b',
'|Halon1211',
'|Halon1202',
'|Halon1301',
'|Halon2402',
'|CH3Br',
'|CH3Cl',
])

# Assume that units coming out of aneris don't change. One day I'll do unit parsing
unit_convert = np.ones(40)
unit_convert[1] = molwt.C/molwt.CO2/1000
unit_convert[2] = molwt.C/molwt.CO2/1000
unit_convert[4] = molwt.N2/molwt.N2O/1000
unit_convert[5] = molwt.S/molwt.SO2
unit_convert[8] = molwt.N/molwt.NO2

years_future = [2015] + list(range(2020,2501,10))
for i, specie in enumerate(emissions_file_species):
data_out[:first_row,i+1] = ssp_df.loc[(ssp_df['Scenario']=='ssp245')&(ssp_df['Variable'].str.endswith(specie)),str(startyear):'2014']*unit_convert[i+1]
if i<23:
f = interp1d(years, scmdf[scmdf.index.get_level_values('variable').str.endswith(species[i])])
data_out[first_row:(last_row+1), i+1] = f(np.arange(first_scenyear, last_scenyear+1))*unit_convert[i+1]
first_scen_row = int(first_scenyear-startyear)
last_scen_row = int(last_scenyear-startyear)

for i, (specie, unit, context) in enumerate(EMISSIONS_SPECIES_UNITS_CONTEXT):
data_out[:first_scen_row, i+1] = ssp_df.filter(
variable="*{}".format(specie),
region="World",
scenario="ssp245",
year=range(startyear, 2015)
).convert_unit(unit, context=context).values.squeeze()

if i < 23:
if not any([specie in v for v in scmdf.get_unique_meta("variable")]):
raise AssertionError("{} not available in scmdf".format(specie))

f = interp1d(
years,
scmdf.filter(
variable="*{}".format(specie),
region="World"
).convert_unit(unit, context=context).values.squeeze()
)
data_out[first_scen_row:(last_scen_row+1), i+1] = f(
np.arange(first_scenyear, last_scenyear+1)
)

else:
f = interp1d(years_future, ssp_df.loc[(ssp_df['Scenario']=='ssp245')&(ssp_df['Variable'].str.endswith(specie)),'2015':'2500'].dropna(axis=1))
data_out[first_row:(last_row+1), i+1] = f(np.arange(first_scenyear, last_scenyear+1))*unit_convert[i+1]
if not any([specie in v for v in ssp_df.get_unique_meta("variable")]):
raise AssertionError("{} not available in ssp_df".format(specie))

filler_data = ssp_df.filter(
scenario="ssp245",
variable="*{}".format(specie),
year=range(2015, 2500 + 1),
)

f = interp1d(
filler_data["year"].values,
filler_data.convert_unit(unit, context=context).values.squeeze()
)
data_out[first_scen_row:(last_scen_row+1), i+1] = f(
np.arange(first_scenyear, last_scenyear+1)
)

return data_out
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def readme():
zip_safe=False,
extras_require={
'docs': ['sphinx>=1.4', 'nbsphinx'],
'dev' : ['notebook', 'wheel', 'twine'],
'dev' : ['notebook', 'scmdata<0.6', 'wheel', 'twine'],
'test': ['pytest>=4.0', 'nbval', 'pytest-cov', 'codecov']
}
)
Loading

0 comments on commit 639bdd1

Please sign in to comment.