Real: Pliocene Equilibrium Reconstruction

Real: Pliocene Equilibrium Reconstruction#

[1]:
%load_ext autoreload
%autoreload 2

import os
os.chdir('/glade/work/fengzhu/GitHub/cfr/docsrc/v2026/notebooks')
import pandas as pd
import xarray as xr
import numpy as np
import glob
from tqdm import tqdm
import cfr
cfr.use('v2026')
print(cfr.__version__)
2026.6.25
[2]:
dirpath = '/lustre/desc1/p/uazn0050/fengzhu/PlioDA'
paths = sorted(glob.glob(os.path.join(dirpath, 'prior', f'*.nc')))
ds = {}
for path in tqdm(paths):
    name = os.path.splitext(os.path.basename(path))[0]
    ds[name] = xr.open_dataset(path)
100%|██████████| 70/70 [00:06<00:00, 10.93it/s]
[3]:
df = pd.read_excel(os.path.join(dirpath, 'prior', 'TableS3_ModelPrior.xlsx'))
plio_run_names = df['PlioceneRunName'].values
pi_run_names = df['PlioceneRunName'].values
[4]:
pm_list = []
for name in plio_run_names:
    # print(name)
    pm_list.append(cfr.PriorMember(ds[name]))
[5]:
%%time
prior = cfr.Prior(pm_list)
prior.ds
CPU times: user 341 ms, sys: 1.68 s, total: 2.02 s
Wall time: 3.06 s
[5]:
<xarray.Dataset> Size: 1GB
Dimensions:  (ens: 37, month: 12, lat: 180, lon: 360)
Coordinates:
  * month    (month) float64 96B 1.0 2.0 3.0 4.0 5.0 ... 8.0 9.0 10.0 11.0 12.0
  * lat      (lat) float64 1kB -89.5 -88.5 -87.5 -86.5 ... 86.5 87.5 88.5 89.5
  * lon      (lon) float64 3kB 0.5 1.5 2.5 3.5 4.5 ... 356.5 357.5 358.5 359.5
Dimensions without coordinates: ens
Data variables:
    pr       (month, lat, lon, ens) float64 230MB 0.1576 0.1568 ... 0.6204
    tas      (month, lat, lon, ens) float64 230MB 249.2 248.9 ... 254.0 253.9
    tos      (month, lat, lon, ens) float64 230MB nan nan nan ... -1.725 -1.741
    sos      (month, lat, lon, ens) float64 230MB nan nan nan ... 30.96 31.19
    siconc   (month, lat, lon, ens) float64 230MB 0.0 nan 0.0 ... 98.84 99.38
    ev       (month, lat, lon, ens) float64 230MB 0.07027 0.0386 ... -0.01667
[6]:
df = pd.read_csv(os.path.join(dirpath, 'proxy', 'df_proxy_midPliocene.csv'))
obs = cfr.Obs(df)
obs.setup()
obs.df
[6]:
pid lat lon depth type seasonality time value R psm_name species clean
0 DSDP516.Mg/Ca -30.646322 324.994450 1313.0 Mg/Ca 1,2,3,4,5,6,12 3.25 1.153137 0.0169 MgCa sacculifer 0.0
1 DSDP552.Mg/Ca 55.593510 345.982189 2301.0 Mg/Ca 1,2,3,4,5,6,7,8,9,10,11,12 3.25 0.899058 0.0169 MgCa bulloides 0.0
2 DSDP590.Mg/Ca -32.594207 162.898037 1299.0 Mg/Ca 1,2,3,4,5,12 3.25 1.157111 0.0169 MgCa sacculifer 0.0
3 DSDP603.Mg/Ca 35.261855 290.479297 4640.0 Mg/Ca 1,2,3,4,5,6,7,8,9,10,11,12 3.25 1.381721 0.0169 MgCa bulloides 0.0
4 DSDP609.Mg/Ca 49.422589 335.045676 3883.0 Mg/Ca 1,2,3,4,5,6,7,8,9,10,11,12 3.25 0.838967 0.0169 MgCa bulloides 1.0
... ... ... ... ... ... ... ... ... ... ... ... ...
103 ODP959.UK37 3.053953 356.530460 2092.0 UK37 1,2,3,4,5,6,7,8,9,10,11,12 3.25 0.955809 0.0025 UK37 NaN NaN
104 ODP978.UK37 35.655501 357.297471 1929.0 UK37 1,2,3,4,5,6,7,8,9,10,11,12 3.25 0.940120 0.0025 UK37 NaN NaN
105 ODP982.UK37 57.058493 343.381278 1135.0 UK37 1,2,3,4,5,6,7,8,9,10,11,12 3.25 0.611470 0.0025 UK37 NaN NaN
106 ODP999.UK37 12.533555 281.067292 2828.0 UK37 1,2,3,4,5,6,7,8,9,10,11,12 3.25 0.966871 0.0025 UK37 NaN NaN
107 PuntaPiccola.UK37 37.115774 12.130472 NaN UK37 1,2,3,4,5,6,7,8,9,10,11,12 3.25 0.898781 0.0025 UK37 NaN NaN

108 rows × 12 columns

[7]:
%%time

da_solver = cfr.enkf.Solver(prior, obs)
fwd_kws = {
    'MgCa': {
        'age': 3.25,
        'sw': 2,
        'H': 0.74,
    },
    'TEX86': {
        'mode': 'standard',
        'type': 'SST',
    },
    'UK37': {
        'order': 2,
    },
}
da_solver.prep(loc_radius=12000, startover=True, get_clim_kws={'mode': 'each_member'}, **fwd_kws)
>>> Proxy System Modeling: Y = H(X)
Downloading file 'omegaph/GLODAPv2.2016b.OmegaC.nc' from 'https://raw.githubusercontent.com/fzhu2e/PyBAYWATCH-data/main/omegaph/GLODAPv2.2016b.OmegaC.nc' to '/glade/u/home/fengzhu/.cache/pybaywatch'.
octave not found, please see README
100%|████████████████████████████████████████| 103M/103M [00:00<00:00, 149GB/s]
Downloading file 'omegaph/GLODAPv2.2016b.pHtsinsitutp.nc' from 'https://raw.githubusercontent.com/fzhu2e/PyBAYWATCH-data/main/omegaph/GLODAPv2.2016b.pHtsinsitutp.nc' to '/glade/u/home/fengzhu/.cache/pybaywatch'.
100%|████████████████████████████████████████| 103M/103M [00:00<00:00, 229GB/s]
Downloading file 'omegaph/gom.mat' from 'https://raw.githubusercontent.com/fzhu2e/PyBAYWATCH-data/main/omegaph/gom.mat' to '/glade/u/home/fengzhu/.cache/pybaywatch'.
100%|█████████████████████████████████████| 10.7k/10.7k [00:00<00:00, 17.0MB/s]
Downloading file 'params/species_model_params.mat' from 'https://raw.githubusercontent.com/fzhu2e/PyBAYWATCH-data/main/params/species_model_params.mat' to '/glade/u/home/fengzhu/.cache/pybaywatch'.
100%|██████████████████████████████████████| 91.6k/91.6k [00:00<00:00, 135MB/s]
Downloading file 'params/mgsw_iters_v2.mat' from 'https://raw.githubusercontent.com/fzhu2e/PyBAYWATCH-data/main/params/mgsw_iters_v2.mat' to '/glade/u/home/fengzhu/.cache/pybaywatch'.
100%|█████████████████████████████████████| 3.14M/3.14M [00:00<00:00, 5.35GB/s]
Downloading file 'ModelOutput/Output_SpatAg_SST/params_standard.mat' from 'https://raw.githubusercontent.com/fzhu2e/PyBAYWATCH-data/main/ModelOutput/Output_SpatAg_SST/params_standard.mat' to '/glade/u/home/fengzhu/.cache/pybaywatch'.
100%|█████████████████████████████████████| 48.9M/48.9M [00:00<00:00, 87.3GB/s]
Downloading file 'params/bayes_posterior_v2.mat' from 'https://raw.githubusercontent.com/fzhu2e/PyBAYWATCH-data/main/params/bayes_posterior_v2.mat' to '/glade/u/home/fengzhu/.cache/pybaywatch'.
100%|█████████████████████████████████████| 36.6k/36.6k [00:00<00:00, 41.0MB/s]
>>> Annualizing prior w/ season: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
>>> Computing the localization matrix
Processing variables: 100%|██████████| 6/6 [00:03<00:00,  1.62it/s]
CPU times: user 45.6 s, sys: 5.32 s, total: 50.9 s
Wall time: 56.8 s
[8]:
%%time

da_solver.run(debug=True, method='EnSRF')
>>> DA update
Updating time slices: 100%|██████████| 1/1 [00:01<00:00,  1.17s/it]
CPU times: user 552 ms, sys: 352 ms, total: 903 ms
Wall time: 1.21 s

[9]:
obs.clim['tos']
[9]:
<xarray.DataArray 'tos' (site: 108, month: 12, ens: 37)> Size: 384kB
array([[[24.98964428, 25.52079057, 25.5379354 , ..., 26.22998639,
         24.60683721, 24.03946287],
        [26.14605525, 26.68145717, 26.81708031, ..., 27.50632178,
         26.10616433, 25.43292147],
        [26.16318037, 26.62394453, 26.8269065 , ..., 27.65054307,
         26.28907888, 25.64532733],
        ...,
        [20.51508323, 20.65533336, 20.56095535, ..., 22.0505918 ,
         19.97467467, 19.8853713 ],
        [21.47187967, 21.64690884, 21.5836901 , ..., 22.86629721,
         20.95866565, 20.73685943],
        [23.11565247, 23.50138813, 23.45586241, ..., 24.36300985,
         22.5273542 , 22.09731781]],

       [[13.15960312, 13.18999481, 14.73693834, ..., 12.59305271,
         13.26918689, 13.63496439],
        [12.8160487 , 12.85155492, 14.41613352, ..., 12.60536941,
         13.13885234, 13.44034377],
        [12.63055132, 12.73222439, 14.2329644 , ..., 12.66594088,
         13.09130877, 13.33864956],
...
        [28.81588589, 29.11561769, 29.82312085, ..., 28.60266947,
         30.38756534, 30.35128148],
        [28.29479923, 28.58438013, 29.45398586, ..., 28.24714082,
         30.01692973, 29.94374773],
        [27.15237667, 27.44973652, 28.46498738, ..., 27.63690315,
         28.71819758, 28.68152386]],

       [[17.27940641, 18.46155153, 18.72935137, ..., 18.59167975,
         18.40038276, 18.32360715],
        [16.41073158, 17.60390502, 17.72796664, ..., 17.77028834,
         17.51002993, 17.34150959],
        [16.32921453, 17.52017026, 17.56754889, ..., 17.59238945,
         17.42921482, 17.18558818],
        ...,
        [24.45341295, 25.92965281, 25.81198479, ..., 24.59160362,
         25.74319989, 24.85062058],
        [21.50087597, 22.86761732, 23.12571876, ..., 22.41095442,
         22.88933679, 22.33521951],
        [18.99029965, 20.17563533, 20.60739092, ..., 20.17687656,
         20.19481303, 20.04177951]]], shape=(108, 12, 37))
Coordinates:
  * site     (site) object 864B 'DSDP516.Mg/Ca' ... 'PuntaPiccola.UK37'
  * month    (month) float64 96B 1.0 2.0 3.0 4.0 5.0 ... 8.0 9.0 10.0 11.0 12.0
  * ens      (ens) int64 296B 0 1 2 3 4 5 6 7 8 9 ... 28 29 30 31 32 33 34 35 36
    lat      (site, ens) float64 32kB -30.5 -30.5 -30.5 -30.5 ... 37.5 37.5 37.5
    lon      (site, ens) float64 32kB 324.5 324.5 324.5 324.5 ... 12.5 12.5 12.5
Attributes:
    Description:  Sea surface temperature
    Units:        Celsius
[10]:
obs.records['AND1B.TEX86'].psm.clim
[10]:
<xarray.Dataset> Size: 2kB
Dimensions:  (ens: 37)
Coordinates:
  * ens      (ens) int64 296B 0 1 2 3 4 5 6 7 8 9 ... 28 29 30 31 32 33 34 35 36
    lat      (ens) float64 296B -77.5 -77.5 -77.5 -77.5 ... -77.5 -76.5 -76.5
    lon      (ens) float64 296B 165.5 165.5 165.5 165.5 ... 171.5 165.5 165.5
    site     <U11 44B 'AND1B.TEX86'
Data variables:
    sos      (ens) float64 296B 34.71 34.08 34.33 33.85 ... 34.27 34.26 34.15
    tos      (ens) float64 296B -1.755 -1.106 -1.626 ... 2.654 -0.7089 -1.034
[11]:
da_solver.obs.df
[11]:
pid lat lon depth type seasonality time value R psm_name species clean pseudo Ym
0 DSDP516.Mg/Ca -30.646322 324.994450 1313.0 Mg/Ca 1,2,3,4,5,6,12 3.25 1.153137 0.0169 MgCa sacculifer 0.0 [1.0475985789968556, 1.0840266910980385, 1.084... 1.063031
1 DSDP552.Mg/Ca 55.593510 345.982189 2301.0 Mg/Ca 1,2,3,4,5,6,7,8,9,10,11,12 3.25 0.899058 0.0169 MgCa bulloides 0.0 [0.8790122833288491, 0.9304375599758773, 0.997... 0.785512
2 DSDP590.Mg/Ca -32.594207 162.898037 1299.0 Mg/Ca 1,2,3,4,5,12 3.25 1.157111 0.0169 MgCa sacculifer 0.0 [1.0078668290061659, 1.0693127594208578, 1.064... 1.056172
3 DSDP603.Mg/Ca 35.261855 290.479297 4640.0 Mg/Ca 1,2,3,4,5,6,7,8,9,10,11,12 3.25 1.381721 0.0169 MgCa bulloides 0.0 [1.3526891904768947, 1.43754172903691, 1.41165... 1.330346
4 DSDP609.Mg/Ca 49.422589 335.045676 3883.0 Mg/Ca 1,2,3,4,5,6,7,8,9,10,11,12 3.25 0.838967 0.0169 MgCa bulloides 1.0 [0.6706339455958514, 0.8230265774912799, 0.756... 0.528415
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
103 ODP959.UK37 3.053953 356.530460 2092.0 UK37 1,2,3,4,5,6,7,8,9,10,11,12 3.25 0.955809 0.0025 UK37 NaN NaN [0.9748423127669279, 0.9783112988235072, 0.982... 0.973247
104 ODP978.UK37 35.655501 357.297471 1929.0 UK37 1,2,3,4,5,6,7,8,9,10,11,12 3.25 0.940120 0.0025 UK37 NaN NaN [0.7704574251030296, 0.7984664965587505, 0.822... 0.753707
105 ODP982.UK37 57.058493 343.381278 1135.0 UK37 1,2,3,4,5,6,7,8,9,10,11,12 3.25 0.611470 0.0025 UK37 NaN NaN [0.551810302904041, 0.5562428402868642, 0.6039... 0.492307
106 ODP999.UK37 12.533555 281.067292 2828.0 UK37 1,2,3,4,5,6,7,8,9,10,11,12 3.25 0.966871 0.0025 UK37 NaN NaN [0.9369960402682951, 0.940948717815467, 0.9622... 0.946704
107 PuntaPiccola.UK37 37.115774 12.130472 NaN UK37 1,2,3,4,5,6,7,8,9,10,11,12 3.25 0.898781 0.0025 UK37 NaN NaN [0.7789384208648916, 0.8155885819627052, 0.827... 0.760645

108 rows × 14 columns

[12]:
print('Prior')
gmst = da_solver.prior.ds['tas'].mean('ens').x.geo_mean().values - 273.15
print(f'GMST = {gmst:.2f}')
gmsst = da_solver.prior.ds['tos'].mean('ens').x.geo_mean().values
print(f'GMSST = {gmsst:.2f}')

print('Posterior')
gmst = da_solver.post['tas'].isel(time=0).mean('ens').x.geo_mean().values - 273.15
print(f'GMST = {gmst:.2f}')
gmsst = da_solver.post['tos'].isel(time=0).mean('ens').x.geo_mean().values
print(f'GMSST = {gmsst:.2f}')
Prior
GMST = 16.00
GMSST = 19.84
Posterior
GMST = 17.29
GMSST = 20.67
[13]:
ds_Jess = xr.open_dataset(os.path.join(dirpath, 'recons', 'pliomip-cloud_Loc24_locFixed.nc'))
ds_Jess
[13]:
<xarray.Dataset> Size: 22MB
Dimensions:        (time: 3, lat: 180, lon: 360, month: 12)
Coordinates:
  * time           (time) float64 24B 0.0 3.25 4.75
  * lat            (lat) float64 1kB -89.5 -88.5 -87.5 -86.5 ... 87.5 88.5 89.5
  * lon            (lon) float64 3kB 0.5 1.5 2.5 3.5 ... 356.5 357.5 358.5 359.5
  * month          (month) float64 96B 1.0 2.0 3.0 4.0 ... 9.0 10.0 11.0 12.0
Data variables: (12/14)
    pr_annual      (time, lat, lon) float64 2MB ...
    pr_DJF         (time, lat, lon) float64 2MB ...
    pr_JJA         (time, lat, lon) float64 2MB ...
    ev_annual      (time, lat, lon) float64 2MB ...
    ev_DJF         (time, lat, lon) float64 2MB ...
    ev_JJA         (time, lat, lon) float64 2MB ...
    ...             ...
    tas_JJA        (time, lat, lon) float64 2MB ...
    siconc_annual  (time, lat, lon) float64 2MB ...
    siconc_DJF     (time, lat, lon) float64 2MB ...
    siconc_JJA     (time, lat, lon) float64 2MB ...
    tos_annual     (time, lat, lon) float64 2MB ...
    sos_annual     (time, lat, lon) float64 2MB ...
[16]:
%%time
da_Feng = da_solver.post['tos'].mean('ens')
da_Jess = ds_Jess['tos_annual'].isel(time=1)

fig, ax = da_Feng.x.plot(
    levels=np.linspace(0, 40, 21),
    cbar_kwargs={'ticks': np.linspace(0, 40, 11)},
    cmap='RdBu_r',
    title='Posterior (Feng)',
    df_sites=obs.df[['lat', 'lon', 'type']],
    site_marker_dict={
        'Mg/Ca': 'o',
        'UK37': 's',
        'TEX86': '^',
    },
    count_site_num=True,
    lgd_kws={'bbox_to_anchor': (0, -0.2)},
)

fig, ax = da_Jess.x.plot(
    levels=np.linspace(0, 40, 21),
    cbar_kwargs={'ticks': np.linspace(0, 40, 11)},
    cmap='RdBu_r',
    title='Posterior (Jess)',
    df_sites=df[['lat', 'lon', 'type']],
    site_marker_dict={
        'Mg/Ca': 'o',
        'UK37': 's',
        'TEX86': '^',
    },
    count_site_num=True,
    lgd_kws={'bbox_to_anchor': (0, -0.2)},
)


fig, ax = (da_Feng - da_Jess).x.plot(
    levels=np.linspace(-0.2, 0.2, 11),
    cbar_kwargs={'ticks': np.linspace(-0.2, 0.2, 11)},
    cmap='RdBu_r',
    title='Diff (tos)',
    df_sites=df[['lat', 'lon', 'type']],
    site_marker_dict={
        'Mg/Ca': 'o',
        'UK37': 's',
        'TEX86': '^',
    },
    count_site_num=True,
    lgd_kws={'bbox_to_anchor': (0, -0.2)},
)
CPU times: user 998 ms, sys: 0 ns, total: 998 ms
Wall time: 996 ms
../_images/notebooks_da-real-PlioDA_14_1.png
../_images/notebooks_da-real-PlioDA_14_2.png
../_images/notebooks_da-real-PlioDA_14_3.png
[15]:
np.max(np.abs(da_Feng - da_Jess))
[15]:
<xarray.DataArray ()> Size: 8B
array(0.14067962)
Attributes:
    Units:    Celsius
[ ]: