<jupyter_start><jupyter_text>Calculate Seasonal ENSO Skill of the NMME model NCEP-CFSv2  In this example, we demonstrate: 1. How to remotely access data from the North American Multi-model Ensemble (NMME) hindcast database and set it up to be used in `climpred`2. How to calculate the Anomaly Correlation Coefficient (ACC) using seasonal data  The North American Multi-model Ensemble (NMME)Further information on NMME is available from [Kirtman et al. 2014](https://journals.ametsoc.org/doi/full/10.1175/BAMS-D-12-00050.1) and the [NMME project website](https://www.cpc.ncep.noaa.gov/products/NMME/)The NMME public database is hosted on the International Research Institute for Climate and Society (IRI) data server http://iridl.ldeo.columbia.edu/SOURCES/.Models/.NMME/  DefinitionsAnomalies: Departure from normal, where normal is defined as the climatological value based on the average value for each month over all years.Nino3.4: An index used to represent the evolution of the El Nino-Southern Oscillation (ENSO). Calculated as the average sea surface temperature (SST) anomalies in the region 5S-5N; 190-240<jupyter_code>import matplotlib.pyplot as plt
import xarray as xr
import pandas as pd
import numpy as np

from climpred import HindcastEnsemble
import climpred
def decode_cf(ds, time_var):
    """Decodes time dimension to CFTime standards."""
    if ds[time_var].attrs['calendar'] == '360':
        ds[time_var].attrs['calendar'] = '360_day'
    ds = xr.decode_cf(ds, decode_times=True)
    return ds<jupyter_output><empty_output><jupyter_text>Load the monthly sea surface temperature (SST) hindcast data for the NCEP-CFSv2 model from the data server<jupyter_code># Get NMME data for NCEP-CFSv2, SST
url = 'http://iridl.ldeo.columbia.edu/SOURCES/.Models/.NMME/NCEP-CFSv2/.HINDCAST/.MONTHLY/.sst/dods'
fcstds = xr.open_dataset(url, decode_times=False, chunks={'S': 1, 'L': 12})
fcstds = decode_cf(fcstds, 'S')
fcstds<jupyter_output><empty_output><jupyter_text>The NMME data dimensions correspond to the following `climpred` dimension definitions: `X=lon`,`L=lead`,`Y=lat`,`M=member`, `S=init`.  We will rename the dimensions to their `climpred` names.<jupyter_code>fcstds=fcstds.rename({'S': 'init',
                      'L': 'lead',
                      'M': 'member',
                      'X': 'lon',
                      'Y': 'lat'})<jupyter_output><empty_output><jupyter_text>Let's make sure that the `lead` dimension is set properly for `climpred`.  NMME data stores `leads` as 0.5, 1.5, 2.5, etc, which correspond to 0, 1, 2, ... months since initialization. We will change the `lead` to be integers starting with zero.<jupyter_code>fcstds['lead'] = (fcstds['lead'] - 0.5).astype('int')<jupyter_output><empty_output><jupyter_text>Next, we want to get the verification SST data from the data server<jupyter_code>obsurl='http://iridl.ldeo.columbia.edu/SOURCES/.Models/.NMME/.OIv2_SST/.sst/dods'
verifds = decode_cf(xr.open_dataset(obsurl, decode_times=False),'T')
verifds<jupyter_output><empty_output><jupyter_text>Rename the dimensions to correspond to `climpred` dimensions<jupyter_code>verifds = verifds.rename({'T': 'time',
                          'X': 'lon',
                          'Y': 'lat'})<jupyter_output><empty_output><jupyter_text>Convert the `time` data to be on the first of the month and in the same calendar format as the forecast output. The time dimension is natively decoded to start in February, even though it starts in January. It is also labelled as mid-month, and we need to label it as the start of the month to ensure that the dates align properly.<jupyter_code>verifds['time'] = xr.cftime_range(start='1982-01', periods=verifds['time'].size, freq='MS', calendar='360_day')<jupyter_output><empty_output><jupyter_text>Subset the data to 1982-2010<jupyter_code>verifds = verifds.sel(time=slice('1982-01-01', '2010-12-01'))
fcstds = fcstds.sel(init=slice('1982-01-01', '2010-12-01'))<jupyter_output><empty_output><jupyter_text>Calculate the Nino3.4 index for forecast and verification<jupyter_code>fcstnino34=fcstds.sel(lat=slice(-5, 5), lon=slice(190, 240)).mean(['lat','lon'])
verifnino34=verifds.sel(lat=slice(-5, 5), lon=slice(190, 240)).mean(['lat','lon'])

fcstclimo = fcstnino34.groupby('init.month').mean('init')
fcstanoms = (fcstnino34.groupby('init.month') - fcstclimo)

verifclimo = verifnino34.groupby('time.month').mean('time')
verifanoms = (verifnino34.groupby('time.month') - verifclimo)

print(fcstanoms)
print(verifanoms)<jupyter_output><xarray.Dataset>
Dimensions:  (init: 348, lead: 10, member: 24)
Coordinates:
  * member   (member) float32 1.0 2.0 3.0 4.0 5.0 ... 20.0 21.0 22.0 23.0 24.0
  * lead     (lead) int64 0 1 2 3 4 5 6 7 8 9
  * init     (init) object 1982-01-01 00:00:00 ... 2010-12-01 00:00:00
    month    (init) int64 1 2 3 4 5 6 7 8 9 10 11 ... 2 3 4 5 6 7 8 9 10 11 12
Data variables:
    sst      (init, lead, member) float32 dask.array<chunksize=(1, 10, 24), meta=np.ndarray>
<xarray.Dataset>
Dimensions:  (time: 348)
Coordinates:
  * time     (time) object 1982-01-01 00:00:00 ... 2010-12-01 00:00:00
    month    (time) int64 1 2 3 4 5 6 7 8 9 10 11 ... 2 3 4 5 6 7 8 9 10 11 12
Data variables:
    sst      (time) float32 0.14492226 -0.044160843 ... -1.5685654 -1.6083965<jupyter_text>Make Seasonal Averages with `center=True` and drop NaNs.<jupyter_code>%%time
fcstnino34seas = fcstanoms.rolling(lead=3, center=True).mean().dropna(dim='lead')
verifnino34seas = verifanoms.rolling(time=3, center=True).mean().dropna(dim='time')<jupyter_output>CPU times: user 4.31 s, sys: 2.29 s, total: 6.6 s
Wall time: 2min 23s<jupyter_text>Create new `xr.DataArray` with seasonal data<jupyter_code># Grab only every three months, which center the seasonal averages.
nleads = fcstnino34seas['lead'].isel(lead=slice(0, None, 3)).size
fcst = xr.DataArray(fcstnino34seas['sst'].isel(lead=slice(0, None, 3)), 
                    coords={'init' : fcstnino34seas['init'],
                            'lead': np.arange(0, nleads),
                            'member': fcstanoms['member'],
                            },
                    dims=['init','lead','member'])
fcst = fcst.rename('sst')<jupyter_output><empty_output><jupyter_text>Assign the `units` attribute of `seasons` to the `lead` dimension, which will align leads based on 3-month increments.<jupyter_code>fcst['lead'].attrs = {'units': 'seasons'}<jupyter_output><empty_output><jupyter_text>Create a `climpred HindcastEnsemble` object<jupyter_code>hindcast = HindcastEnsemble(fcst)
hindcast = hindcast.add_observations(verifnino34seas)<jupyter_output><empty_output><jupyter_text>Compute the Anomaly Correlation Coefficient (ACC) 0, 1, 2, and 3 season lead-times<jupyter_code>skillds = hindcast.verify(metric='acc', comparison='e2o', dim='init', alignment='maximize')
skillds<jupyter_output><empty_output><jupyter_text>Make bar plot of Nino3.4 skill for 0,1, and 2 season lead times<jupyter_code>x=np.arange(0,nleads,1.0).astype(int)
plt.bar(x,skillds['sst'])
plt.xticks(x)
plt.title('NCEP-CFSv2 Nino34 ACC')
plt.xlabel('Lead (Season)')
plt.ylabel('ACC')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13260289366484057, 'fraction_numerical': 0.05450203680292176, 'mean_word_length': 4.571205007824726, 'pattern_counts': {'":': 0, '<': 62, '<?xml version=': 0, '>': 62, 'https://': 2, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 5, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '15', 'dir': 'jupyter-structured-clean-dedup', 'id': '205949', 'license': 'MIT', 'n_tokens_mistral': 2868, 'n_tokens_neox': 2530, 'n_words': 661, 'path': 'docs/source/examples/monseas/seasonal-enso-subx-example.ipynb', 'repo_name': 'kpegion/climpred', 'size': '7119'}