Generating a Table of Global Fluxes¶
This notebook reads time series data from Make Timeseries.ipynb
and
generates a table containing values listed in issue #6
This notebook uses several python packages¶
The watermark package shows the version number used to help others recreate this environment.
import pandas as pd
import ann_avg_utils as aau
# Set pandas option and get pint units
pd.set_option('display.max_colwidth', 75)
units, final_units = aau.get_pint_units()
%load_ext watermark
%watermark -d -iv -m -g -h
Compiler : GCC 9.3.0
OS : Linux
Release : 3.10.0-1127.18.2.el7.x86_64
Machine : x86_64
Processor : x86_64
CPU cores : 72
Architecture: 64bit
Hostname: crhtc50
Git hash: d554567d1893e0b92b8e04d39cdfe8ccf8aefef4
pandas: 1.2.4
json : 2.0.9
sys : 3.7.10 | packaged by conda-forge | (default, Feb 19 2021, 16:07:37)
[GCC 9.3.0]
Reduce Data Sets¶
Data has been reduced to annual means, but the netcdf files contain every year in the dataset. For generating tables, we want to look at specific time periods.
# aau.print_exp_time_bounds(ann_avg[vars[0]], time_slices)
Define labels for rows in each table¶
Also determine correct number of digits to write each value out to
table_specs = aau.get_table_specs(final_units, o2_levs=[5, 20, 60, 80])
Average over all ensemble members and time (for proper time period)¶
diagnostic_values = aau.compute_diagnostic_values(experiments,
table_specs,
ann_avg,
time_slices,
cesm_units,
final_units,
experiment_span,
verbose=False)
* Can not compute SiO2_FLUX_100m for cesm1_PI
* Can not compute NHx_SURFACE_EMIS for cesm1_PI
* Can not compute SedDenitrif for cesm1_PI
* Can not compute ponToSed for cesm1_PI
* Can not compute DON_RIV_FLUX for cesm1_PI
* Can not compute DONr_RIV_FLUX for cesm1_PI
* Can not compute NO3_RIV_FLUX for cesm1_PI
* No additional denitrification terms for cesm1_PI
* Can not compute SiO2_FLUX_100m for cesm1_PI_esm
* Can not compute NHx_SURFACE_EMIS for cesm1_PI_esm
* Can not compute SedDenitrif for cesm1_PI_esm
* Can not compute ponToSed for cesm1_PI_esm
* Can not compute DON_RIV_FLUX for cesm1_PI_esm
* Can not compute DONr_RIV_FLUX for cesm1_PI_esm
* Can not compute NO3_RIV_FLUX for cesm1_PI_esm
* No additional denitrification terms for cesm1_PI_esm
* Can not compute SiO2_FLUX_100m for cesm1_hist
* Can not compute NHx_SURFACE_EMIS for cesm1_hist
* Can not compute SedDenitrif for cesm1_hist
* Can not compute ponToSed for cesm1_hist
* Can not compute DON_RIV_FLUX for cesm1_hist
* Can not compute DONr_RIV_FLUX for cesm1_hist
* Can not compute NO3_RIV_FLUX for cesm1_hist
* No additional denitrification terms for cesm1_hist
* Can not compute SiO2_FLUX_100m for cesm1_hist_esm
* Can not compute NHx_SURFACE_EMIS for cesm1_hist_esm
* Can not compute SedDenitrif for cesm1_hist_esm
* Can not compute ponToSed for cesm1_hist_esm
* Can not compute DON_RIV_FLUX for cesm1_hist_esm
* Can not compute DONr_RIV_FLUX for cesm1_hist_esm
* Can not compute NO3_RIV_FLUX for cesm1_hist_esm
* No additional denitrification terms for cesm1_hist_esm
* Can not compute SiO2_FLUX_100m for cesm1_RCP85
* Can not compute NHx_SURFACE_EMIS for cesm1_RCP85
* Can not compute SedDenitrif for cesm1_RCP85
* Can not compute ponToSed for cesm1_RCP85
* Can not compute DON_RIV_FLUX for cesm1_RCP85
* Can not compute DONr_RIV_FLUX for cesm1_RCP85
* Can not compute NO3_RIV_FLUX for cesm1_RCP85
* No additional denitrification terms for cesm1_RCP85
* Can not compute SiO2_FLUX_100m for cesm1_hist_RCP85
* Can not compute NHx_SURFACE_EMIS for cesm1_hist_RCP85
* Can not compute SedDenitrif for cesm1_hist_RCP85
* Can not compute ponToSed for cesm1_hist_RCP85
* Can not compute DON_RIV_FLUX for cesm1_hist_RCP85
* Can not compute DONr_RIV_FLUX for cesm1_hist_RCP85
* Can not compute NO3_RIV_FLUX for cesm1_hist_RCP85
* No additional denitrification terms for cesm1_hist_RCP85
Actually make the tables¶
def make_table(table_specs, table_vars, test_exps):
table_dict = dict()
table_dict['Flux or Concentration'] = []
for varname in table_vars:
# Unpack dictionaries in diag_columns
table_key = table_specs[varname]['key']
units = table_specs[varname]['units']
rounding = table_specs[varname]['rounding']
# Get row header
if units:
row_header = f'{table_key} ({units})'
else:
row_header = table_key
table_dict['Flux or Concentration'].append(row_header)
# Get values rounded to correct number of digits
for exp in test_exps:
if experiment_longnames[exp] not in table_dict:
table_dict[experiment_longnames[exp]] = []
# Workaround to drop decimal place when rounding to nearest integer
if exp != 'diff':
round_to = rounding
else:
round_to = 3
format = f'0.{round_to}f'
try:
rounded_val = f'{diagnostic_values[exp][table_key].magnitude:{format}}'
table_dict[experiment_longnames[exp]].append(rounded_val)
# Add asterisk denoting CESM1 integrals are 150m, not full depth
if ('cesm1' in exp) and (varname in ['NPP', 'NPP_diat']):
table_dict[experiment_longnames[exp]][-1] = table_dict[experiment_longnames[exp]][-1] + '*'
except:
table_dict[experiment_longnames[exp]].append('-')
return(table_dict)
if 'cesm1_PI_esm' in diagnostic_values:
if global_vars["include_marg_seas"]:
print('Comparison of cesm1_PI_esm')
# let var = fg_co2[d=2]
# show var var
# VAR = FG_CO2[D=2]
# list var_integral_PgC_year
# VARIABLE : (1E-9 * 12 * 1E-15 * 86400 * 365) * VAR_MUL_AREA[I=@SUM,J=@SUM]
# X : 0.5 to 320.5
# Y : 0.5 to 384.5
# ENSEMBLE : 0421
# -0.02491
if table_specs['CO2']['key'] in diagnostic_values["cesm1_PI_esm"]:
print(f'FG_CO2: {diagnostic_values["cesm1_PI_esm"][table_specs["CO2"]["key"]].magnitude:0.5f} (should be -0.02491)')
# let var = POC_FLUX_IN_100m[d=2]
# show var var
# VAR = POC_FLUX_IN_100M[D=2]
# list/prec=6 var_integral_PgC_year
# VARIABLE : (1E-9 * 12 * 1E-15 * 86400 * 365) * VAR_MUL_AREA[I=@SUM,J=@SUM]
# X : 0.5 to 320.5
# Y : 0.5 to 384.5
# ENSEMBLE : 0421
# 8.06490
if table_specs['POC']['key'] in diagnostic_values["cesm1_PI_esm"]:
print(f'POC_FLUX_IN_100m: {diagnostic_values["cesm1_PI_esm"][table_specs["POC"]["key"]].magnitude:0.5f} (should be 8.06490)')
# let var = photoC_diat_zint_100m[d=2]+photoC_sp_zint_100m[d=2]+photoC_diaz_zint_100m[d=2]
# show var var
# VAR = PHOTOC_DIAT_ZINT_100M[D=2]+PHOTOC_SP_ZINT_100M[D=2]+PHOTOC_DIAZ_ZINT_100M[D=2]
# list/prec=6 var_integral_PgC_year
# VARIABLE : (1E-9 * 12 * 1E-15 * 86400 * 365) * VAR_MUL_AREA[I=@SUM,J=@SUM]
# X : 0.5 to 320.5
# Y : 0.5 to 384.5
# ENSEMBLE : 0421
# 55.4878
if table_specs['NPP_100m']['key'] in diagnostic_values["cesm1_PI_esm"]:
print(f'photoC_diat_zint_100m: {diagnostic_values["cesm1_PI_esm"][table_specs["NPP_100m"]["key"]].magnitude:0.4f} (should be 55.4878)')
else:
print("Comparison of CESM1 values is only done when including marginal seas in global averages")
else:
print('No comparisons done, since cesm1_PI_esm experiment not included')
Comparison of CESM1 values is only done when including marginal seas in global averages
# Keith L's table
table_vars = ['CO2', 'NPP_100m', 'POC']
# Match number of digits in orginal paper
table_specs['CO2']['rounding'] = 3
table_specs['NPP_100m']['rounding'] = 2
# Add difference column
new_exp = 'diff'
diagnostic_values[new_exp] = dict()
experiment_longnames[new_exp] = 'Difference'
for table_key in table_specs:
table_spec = table_specs[table_key]
if ('cesm1_hist' in diagnostic_values) and ('cesm1_PI' in diagnostic_values):
try:
# If key has not been populated, we want a dash here
diagnostic_values[new_exp][table_spec['key']] = diagnostic_values['cesm1_hist'][table_spec['key']] - diagnostic_values['cesm1_PI'][table_spec['key']]
except:
diagnostic_values[new_exp][table_spec['key']] = '-'
else:
diagnostic_values[new_exp][table_spec['key']] = '-'
pd.DataFrame(make_table(table_specs, table_vars, ['cesm1_PI', 'cesm1_hist', new_exp])).set_index("Flux or Concentration")
preindustrial (CESM1) | 1981-2005 (CESM1) | Difference | |
---|---|---|---|
Flux or Concentration | |||
Air-sea CO$_2$ flux (PgC/yr) | -0.023 | 1.773 | 1.796 |
Net primary production, top 100m (PgC/yr) | 55.35 | 55.53 | 0.178 |
Sinking POC at 100 m (PgC/yr) | 8.07 | 8.00 | -0.074 |
# Keith M's original table
# We use a different set of preindustrial years
# Also, maybe he uses equal weighting for month -> year instead of number of days per month?
table_specs['CO2']['rounding'] = 2
table_specs['NPP_100m']['rounding'] = 1
test_exps = ['cesm1_PI_esm', 'cesm1_hist_esm', 'cesm1_RCP45', 'cesm1_RCP85']
table_vars = ['NPP', 'NPP_100m', 'POC', 'CaCO3', 'rain', 'Nfix', 'Ndep', 'denitrif',
'Ncycle', 'CO2', 'NPP_diat', 'NPP_diat_100m', 'O2', 'o2_under_20']
pd.DataFrame(make_table(table_specs, table_vars, test_exps)).set_index("Flux or Concentration")
preindustrial (CESM1, BPRP) | 1990s (CESM1) | RCP 4.5 2090s (CESM1) | RCP 8.5 2090s (CESM1) | |
---|---|---|---|---|
Flux or Concentration | ||||
Net primary production, full depth (PgC/yr) | 55.8* | 56.3* | - | 54.0* |
Net primary production, top 100m (PgC/yr) | 55.3 | 55.8 | - | 53.5 |
Sinking POC at 100 m (PgC/yr) | 8.05 | 8.05 | - | 7.20 |
Sinking CaCO$_3$ at 100 m (PgC/yr) | 0.756 | 0.750 | - | 0.723 |
Rain ratio (CaCO$_3$/POC) at 100 m | 0.094 | 0.093 | - | 0.100 |
Nitrogen fixation (TgN/yr) | 176.7 | 173.6 | - | 143.7 |
Nitrogen deposition (TgN/yr) | 6.6 | 29.1 | - | 30.0 |
Water Column Denitrification (TgN/yr) | 189.7 | 193.1 | - | 187.5 |
N cycle imbalance (TgN/yr) | -6.4 | 9.6 | - | -13.8 |
Air-sea CO$_2$ flux (PgC/yr) | -0.02 | 2.18 | - | 4.71 |
Diatom primary production, full depth (\%) | 35* | 35* | - | 32* |
Diatom primary production, top 100m (\%) | 34 | 34 | - | 32 |
Mean ocean oxygen ($\mu$M) | 192 | 190 | - | 183 |
OMZ volume (O$_2$ $<$20 $\mu$M) (10$^1$$^5$ m$^3$) | 37 | 38 | - | 46 |
# Updated table for our paper
table_specs['CO2']['rounding'] = 2
table_specs['NPP_100m']['rounding'] = 1
table_specs['SiO2']['rounding'] = 1
# test_exps = ['cesm2_PI', 'cesm2_hist', 'cesm2_SSP1-2.6', 'cesm2_SSP2-4.5', 'cesm2_SSP3-7.0', 'cesm2_SSP5-8.5']
test_exps = ['cesm1_PI', 'cesm1_hist_RCP85', 'cesm1_RCP85', 'cesm2_PI', 'cesm2_hist', 'cesm2_SSP5-8.5']
table_vars = ['NPP',
# 'NPP_100m',
'POC',
'CaCO3',
'SiO2',
'rain',
'Nfix',
'Ndep',
'denitrif',
'denitrif2',
'Nbury',
'Nemis',
'rivflux',
'Ncycle',
'CO2',
'NPP_diat_100m',
'NPP_diat',
# 'NPP_diat_100m',
# 'O2',
# 'o2_under_20',
# 'o2_under_5',
# 'o2_under_60',
# 'o2_under_80'
]
our_table = pd.DataFrame(make_table(table_specs, table_vars, test_exps))
our_table.set_index("Flux or Concentration")
preindustrial (CESM1) | 1990 - 2014 (CESM1) | RCP 8.5 2090s (CESM1) | preindustrial (CESM2) | 1990-2014 (CESM2) | SSP5-8.5 2090s (CESM2) | |
---|---|---|---|---|---|---|
Flux or Concentration | ||||||
Net primary production, full depth (PgC/yr) | 55.9* | 56.1* | 54.0* | 48.2 | 48.8 | 49.8 |
Sinking POC at 100 m (PgC/yr) | 8.07 | 7.98 | 7.20 | 6.98 | 7.05 | 6.69 |
Sinking CaCO$_3$ at 100 m (PgC/yr) | 0.757 | 0.748 | 0.723 | 0.767 | 0.767 | 0.808 |
Sinking SiO$_2$ at 100 m (Tmol/yr) | - | - | - | 77.6 | 78.3 | 69.9 |
Rain ratio (CaCO$_3$/POC) at 100 m | 0.094 | 0.094 | 0.100 | 0.110 | 0.109 | 0.121 |
Nitrogen fixation (TgN/yr) | 175.3 | 169.4 | 143.7 | 240.6 | 243.1 | 285.0 |
Nitrogen deposition (TgN/yr) | 6.6 | 29.6 | 30.0 | 13.3 | 37.2 | 38.3 |
Water Column Denitrification (TgN/yr) | 190.0 | 193.7 | 187.5 | 184.8 | 191.6 | 255.8 |
Sediment Denitrification (TgN/yr) | - | - | - | 67 | 71 | 68 |
Nitrogen Burial to Sediment (TgN/yr) | - | - | - | 24 | 27 | 22 |
Nitrogen surface emissions (TgN/yr) | - | - | - | 6 | 5 | 3 |
Nitrogen River Flux (TgN/yr) | - | - | - | 13 | 25 | 25 |
N cycle imbalance (TgN/yr) | -8.0 | 5.2 | -13.8 | -14.1 | 10.3 | -0.8 |
Air-sea CO$_2$ flux (PgC/yr) | -0.02 | 2.03 | 4.71 | -0.04 | 2.04 | 5.33 |
Diatom primary production, top 100m (\%) | 34 | 34 | 32 | 35 | 37 | 31 |
Diatom primary production, full depth (\%) | 35* | 35* | 32* | 36 | 37 | 31 |
print(our_table.to_latex(index=False, escape=False))
\begin{tabular}{lllllll}
\toprule
Flux or Concentration & preindustrial (CESM1) & 1990 - 2014 (CESM1) & RCP 8.5 2090s (CESM1) & preindustrial (CESM2) & 1990-2014 (CESM2) & SSP5-8.5 2090s (CESM2) \\
\midrule
Net primary production, full depth (PgC/yr) & 55.9* & 56.1* & 54.0* & 48.2 & 48.8 & 49.8 \\
Sinking POC at 100 m (PgC/yr) & 8.07 & 7.98 & 7.20 & 6.98 & 7.05 & 6.69 \\
Sinking CaCO$_3$ at 100 m (PgC/yr) & 0.757 & 0.748 & 0.723 & 0.767 & 0.767 & 0.808 \\
Sinking SiO$_2$ at 100 m (Tmol/yr) & - & - & - & 77.6 & 78.3 & 69.9 \\
Rain ratio (CaCO$_3$/POC) at 100 m & 0.094 & 0.094 & 0.100 & 0.110 & 0.109 & 0.121 \\
Nitrogen fixation (TgN/yr) & 175.3 & 169.4 & 143.7 & 240.6 & 243.1 & 285.0 \\
Nitrogen deposition (TgN/yr) & 6.6 & 29.6 & 30.0 & 13.3 & 37.2 & 38.3 \\
Water Column Denitrification (TgN/yr) & 190.0 & 193.7 & 187.5 & 184.8 & 191.6 & 255.8 \\
Sediment Denitrification (TgN/yr) & - & - & - & 67 & 71 & 68 \\
Nitrogen Burial to Sediment (TgN/yr) & - & - & - & 24 & 27 & 22 \\
Nitrogen surface emissions (TgN/yr) & - & - & - & 6 & 5 & 3 \\
Nitrogen River Flux (TgN/yr) & - & - & - & 13 & 25 & 25 \\
N cycle imbalance (TgN/yr) & -8.0 & 5.2 & -13.8 & -14.1 & 10.3 & -0.8 \\
Air-sea CO$_2$ flux (PgC/yr) & -0.02 & 2.03 & 4.71 & -0.04 & 2.04 & 5.33 \\
Diatom primary production, top 100m (\%) & 34 & 34 & 32 & 35 & 37 & 31 \\
Diatom primary production, full depth (\%) & 35* & 35* & 32* & 36 & 37 & 31 \\
\bottomrule
\end{tabular}