FLUXES

Author: Lukas Hörtnagl (holukas@ethz.ch)

Imports#

import importlib.metadata
import warnings
from datetime import datetime
from pathlib import Path
import pandas as pd
import matplotlib.pyplot as plt
import diive as dv
from diive.core.io.files import save_parquet, load_parquet
from diive.core.plotting.cumulative import CumulativeYear

warnings.filterwarnings(action='ignore', category=FutureWarning)
warnings.filterwarnings(action='ignore', category=UserWarning)
version_diive = importlib.metadata.version("diive")
print(f"diive version: v{version_diive}")
diive version: v0.87.0

Load data#

SOURCEDIR = r"../80_FINALIZE"
FILENAME = r"81.1_FLUXES_M15_MGMT_L4.2_NEE_GPP_RECO_LE_H_FN2O_FCH4.parquet"
FILEPATH = Path(SOURCEDIR) / FILENAME
df = load_parquet(filepath=FILEPATH)
df
Loaded .parquet file ..\80_FINALIZE\81.1_FLUXES_M15_MGMT_L4.2_NEE_GPP_RECO_LE_H_FN2O_FCH4.parquet (1.005 seconds).
    --> Detected time resolution of <30 * Minutes> / 30min 
.PREC_RAIN_TOT_GF1_0.5_1_MEAN3H-12 .PREC_RAIN_TOT_GF1_0.5_1_MEAN3H-18 .PREC_RAIN_TOT_GF1_0.5_1_MEAN3H-24 .PREC_RAIN_TOT_GF1_0.5_1_MEAN3H-6 .SWC_GF1_0.15_1_gfXG_MEAN3H-12 .SWC_GF1_0.15_1_gfXG_MEAN3H-18 .SWC_GF1_0.15_1_gfXG_MEAN3H-24 .SWC_GF1_0.15_1_gfXG_MEAN3H-6 .TS_GF1_0.04_1_gfXG_MEAN3H-12 .TS_GF1_0.04_1_gfXG_MEAN3H-18 .TS_GF1_0.04_1_gfXG_MEAN3H-24 .TS_GF1_0.04_1_gfXG_MEAN3H-6 .TS_GF1_0.15_1_gfXG_MEAN3H-12 .TS_GF1_0.15_1_gfXG_MEAN3H-18 .TS_GF1_0.15_1_gfXG_MEAN3H-24 ... GPP_NT_CUT_50_gfRF RECO_DT_CUT_50_gfRF GPP_DT_CUT_50_gfRF RECO_DT_CUT_50_gfRF_SD GPP_DT_CUT_50_gfRF_SD G_GF1_0.03_1 G_GF1_0.03_2 G_GF1_0.05_1 G_GF1_0.05_2 G_GF4_0.02_1 G_GF5_0.02_1 LW_OUT_T1_2_1 NETRAD_T1_2_1 PPFD_OUT_T1_2_2 SW_OUT_T1_2_1
TIMESTAMP_MIDDLE
2005-01-01 00:15:00 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... 0.918553 0.093071 0.0 0.080016 0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2005-01-01 00:45:00 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... 0.917972 0.092682 0.0 0.079688 0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2005-01-01 01:15:00 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... 0.163001 0.093071 0.0 0.080016 0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2005-01-01 01:45:00 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... 0.190890 0.093071 0.0 0.080016 0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
2005-01-01 02:15:00 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN ... 0.167042 0.092295 0.0 0.079361 0.0 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
2024-12-31 21:45:00 0.0 0.0 0.0 0.0 52.229004 52.226300 52.226689 52.216796 3.458828 3.150402 3.115260 3.660897 4.335667 4.347764 4.385967 ... -0.334996 1.091028 0.0 0.265808 0.0 NaN NaN -9.097370 -7.880106 NaN NaN 311.167160 -5.883538 0.0 0.0
2024-12-31 22:15:00 0.0 0.0 0.0 0.0 52.227858 52.227986 52.224528 52.214211 3.522570 3.187638 3.103440 3.643396 4.338551 4.342880 4.379524 ... -0.310533 1.078751 0.0 0.264327 0.0 NaN NaN -9.561669 -8.172388 NaN NaN 310.079817 -6.269816 0.0 0.0
2024-12-31 22:45:00 0.0 0.0 0.0 0.0 52.226640 52.229837 52.222456 52.209876 3.578745 3.230037 3.095339 3.624025 4.343767 4.339440 4.372636 ... -0.225651 1.079759 0.0 0.264447 0.0 NaN NaN -10.138718 -8.527732 NaN NaN 309.604987 -6.934394 0.0 0.0
2024-12-31 23:15:00 0.0 0.0 0.0 0.0 52.224375 52.231151 52.221324 52.238293 3.624160 3.278488 3.093806 3.601135 4.350872 4.336333 4.366082 ... -0.558285 1.062164 0.0 0.262373 0.0 NaN NaN -10.649611 -8.871628 NaN NaN 308.812117 -5.696729 0.0 0.0
2024-12-31 23:45:00 0.0 0.0 0.0 0.0 52.222007 52.230632 52.222701 52.273511 3.656167 3.331678 3.103003 3.579020 4.360311 4.334225 4.359530 ... -0.317543 1.047483 0.0 0.260688 0.0 NaN NaN -10.944774 -9.138224 NaN NaN 307.372117 -8.102484 0.0 0.0

350640 rows × 812 columns

List of gap-filled flux variables#

fluxlist = [c for c in df.columns if str(c).endswith("gfRF")];
fluxlist
['NEE_L3.1_L3.3_CUT_16_QCF_gfRF',
 'NEE_L3.1_L3.3_CUT_50_QCF_gfRF',
 'NEE_L3.1_L3.3_CUT_84_QCF_gfRF',
 'LE_L3.1_L3.3_CUT_NONE_QCF_gfRF',
 'H_L3.1_L3.3_CUT_NONE_QCF_gfRF',
 'FN2O_L3.1_L3.3_CUT_16_QCF_gfRF',
 'FN2O_L3.1_L3.3_CUT_50_QCF_gfRF',
 'FN2O_L3.1_L3.3_CUT_84_QCF_gfRF',
 'FCH4_L3.1_L3.3_CUT_16_QCF_gfRF',
 'FCH4_L3.1_L3.3_CUT_50_QCF_gfRF',
 'FCH4_L3.1_L3.3_CUT_84_QCF_gfRF',
 'RECO_NT_CUT_16_gfRF',
 'GPP_NT_CUT_16_gfRF',
 'RECO_DT_CUT_16_gfRF',
 'GPP_DT_CUT_16_gfRF',
 'RECO_NT_CUT_84_gfRF',
 'GPP_NT_CUT_84_gfRF',
 'RECO_DT_CUT_84_gfRF',
 'GPP_DT_CUT_84_gfRF',
 'RECO_NT_CUT_50_gfRF',
 'GPP_NT_CUT_50_gfRF',
 'RECO_DT_CUT_50_gfRF',
 'GPP_DT_CUT_50_gfRF']

Fluxes: gap-filled (random forest)#

Main ecosystem fluxes#

nee = 'NEE_L3.1_L3.3_CUT_50_QCF_gfRF'
le = 'LE_L3.1_L3.3_CUT_NONE_QCF_gfRF'
h = 'H_L3.1_L3.3_CUT_NONE_QCF_gfRF'
n2o = 'FN2O_L3.1_L3.3_CUT_50_QCF_gfRF'
ch4 = 'FCH4_L3.1_L3.3_CUT_50_QCF_gfRF'
gpp = 'GPP_DT_CUT_50_gfRF'
reco = 'RECO_DT_CUT_50_gfRF'
fluxes = [nee, gpp, reco, le, h, n2o, ch4]
fluxes
['NEE_L3.1_L3.3_CUT_50_QCF_gfRF',
 'GPP_DT_CUT_50_gfRF',
 'RECO_DT_CUT_50_gfRF',
 'LE_L3.1_L3.3_CUT_NONE_QCF_gfRF',
 'H_L3.1_L3.3_CUT_NONE_QCF_gfRF',
 'FN2O_L3.1_L3.3_CUT_50_QCF_gfRF',
 'FCH4_L3.1_L3.3_CUT_50_QCF_gfRF']

Flux units: $\( \mathrm{NEE=\mu mol\ CO_{2}\ m^{-2}\ s^{-1}} \)\( \)\( \mathrm{LE=W\ m^{-2}} \)\( \)\( \mathrm{H=W\ m^{-2}} \)\( \)\( \mathrm{N_{2}O=nmol\ N_{2}O\ m^{-2}\ s^{-1}} \)\( \)\( \mathrm{CH_{4}=nmol\ CH_{4}\ m^{-2}\ s^{-1}} \)$

units_nee = r"$\mathrm{\mu mol\ CO_{2}\ m^{-2}\ s^{-1}}$"
units_gpp = r"$\mathrm{\mu mol\ CO_{2}\ m^{-2}\ s^{-1}}$"
units_reco = r"$\mathrm{\mu mol\ CO_{2}\ m^{-2}\ s^{-1}}$"
units_le = r"$\mathrm{W\ m^{-2}}$"
units_h = r"$\mathrm{W\ m^{-2}}$"
units_n2o = r"$\mathrm{nmol\ N_{2}O\ m^{-2}\ s^{-1}}$"
units_ch4 = r"$\mathrm{nmol\ CH_{4}\ m^{-2}\ s^{-1}}$"

Heatmaps (half-hourly fluxes)#

fig, axs = plt.subplots(ncols=7, figsize=(30, 15), dpi=70, layout="constrained")
dv.heatmapdatetime(series=df[nee], cb_digits_after_comma=0, ax=axs[0], zlabel=units_nee).plot()
dv.heatmapdatetime(series=df[gpp], cb_digits_after_comma=0, ax=axs[1], zlabel=units_gpp).plot()
dv.heatmapdatetime(series=df[reco], cb_digits_after_comma=0, ax=axs[2], zlabel=units_reco).plot()
dv.heatmapdatetime(series=df[le], cb_digits_after_comma=0, ax=axs[3], zlabel=units_le).plot()
dv.heatmapdatetime(series=df[h], cb_digits_after_comma=0, ax=axs[4], zlabel=units_h).plot()
dv.heatmapdatetime(series=df[n2o], cb_digits_after_comma=0, ax=axs[5], zlabel=units_n2o).plot()
dv.heatmapdatetime(series=df[ch4], cb_digits_after_comma=0, ax=axs[6], zlabel=units_ch4).plot()
hide_labels = [1, 2, 3, 4, 5, 6]
for h in hide_labels:
    axs[h].axes.get_yaxis().get_label().set_visible(False)
    plt.setp(axs[h].get_yticklabels(), visible=False)
../../_images/0e975940a901ad5f2fb82241c4a707bfe6ffcc14778eb8efec737ad2dd6e15e4.png

Heatmaps (monthly fluxes)#

fig, axs = plt.subplots(ncols=7, figsize=(36, 12), dpi=150, layout="constrained")
fig.suptitle(f'Mean flux per month', fontsize=32)

for ix, f in enumerate(fluxes):
    s = df[f].resample('M').mean()        
    dv.heatmapyearmonth(series_monthly=s, title=s.name, ax=axs[ix], cb_digits_after_comma=0, zlabel="mean flux").plot()

# axs[0].axes.get_yaxis().get_label().set_visible(False)
hide_labels = [1, 2, 3, 4]
for h in hide_labels:
    axs[h].axes.get_yaxis().get_label().set_visible(False)
    plt.setp(axs[h].get_yticklabels(), visible=False)
../../_images/9d29f12a93d1a2b51c4e7c7c8ffa5241f0ae4d314a0c9a25f5d0b7e9f5a77e5c.png

Cumulatives per year#

# Conversion factors and resulting units
conversions = {
    'NEE_L3.1_L3.3_CUT_50_QCF_gfRF': [0.02161926, r'($\mathrm{gC\ m^{-2}}$)'],  # umol CO2 m-2 s-1 --> gC m-2 30min-1
    'GPP_DT_CUT_50_gfRF': [0.02161926, r'($\mathrm{gC\ m^{-2}}$)'],  # umol CO2 m-2 s-1 --> gC m-2 30min-1
    'RECO_DT_CUT_50_gfRF': [0.02161926, r'($\mathrm{gC\ m^{-2}}$)'],  # umol CO2 m-2 s-1 --> gC m-2 30min-1
    'LE_L3.1_L3.3_CUT_NONE_QCF_gfRF': [1800, r'($\mathrm{W\ m^{-2}}$)'],  # W m-2 s-1 --> W m-2 30min-1
    'H_L3.1_L3.3_CUT_NONE_QCF_gfRF': [1800, r'($\mathrm{W\ m^{-2}}$)'],  # W m-2 s-1 --> W m-2 30min-1
    'FN2O_L3.1_L3.3_CUT_50_QCF_gfRF': [0.00050424109632, r'($\mathrm{kg\ N_2O-N\ ha^{-1}}$)'],  # nmol N2O m-2 s-1 --> kg N2O-N ha-1 30min-1
    'FCH4_L3.1_L3.3_CUT_50_QCF_gfRF': [0.000216198, r'($\mathrm{kg\ CH_4-C\ ha^{-1}}$)']  # nmol CH4 m-2 s-1 --> kg CH4-C ha-1 30min-1
}

for f in fluxes:
    s = df[f].multiply(conversions[f][0])
    units = conversions[f][1]

    CumulativeYear(
        series=s,
        series_units=units,
        start_year=2005,
        end_year=2024,
        show_reference=True,
        excl_years_from_reference=None,
        highlight_year=None,
        highlight_year_color='#F44336').plot();
../../_images/bbcfcbea9774eaba083dcb828555c452f423457fe1f376caa9398ebaab1b1891.png ../../_images/a18b3dc4b3df673e373b8f90c5caf84a52e4e08ad81258f5be17133dc7b06d87.png ../../_images/87d80cf43104ee765035e356a767643ef0b206b2e397198e365b1a822c7d22e1.png ../../_images/3920ddb51a75ec845c57a7ded33bd180e86100d7e5e2dbba03177597220a6eb1.png ../../_images/0a5a9c59db521ed07b120fed9b87fccf3b0e34525b3a6d9a3e0943c19c926be5.png ../../_images/643c4373d156dcb9f0b4d39b67dfb0b121b156d24851ae6aca0ee45aa8f4d801.png ../../_images/22b51be2a94d1cd36650dff9d1f275c55bd942371bf0f237f32da78d7b855f54.png

End of notebook#

dt_string = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"Finished. {dt_string}")
Finished. 2025-05-16 16:02:48