Skip to content

Commit

Permalink
Merge branch 'main' into mean_clim_upgrade_lee1043_20240812
Browse files Browse the repository at this point in the history
  • Loading branch information
lee1043 authored Dec 23, 2024
2 parents 7c818bc + 9205c7f commit ee00de6
Show file tree
Hide file tree
Showing 7 changed files with 1,203 additions and 435 deletions.
788 changes: 479 additions & 309 deletions doc/jupyter/Demo/Demo_4_modes_of_variability.ipynb

Large diffs are not rendered by default.

63 changes: 59 additions & 4 deletions pcmdi_metrics/io/xcdat_openxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
import xcdat as xc
import xmltodict

from pcmdi_metrics.io.xcdat_dataset_io import get_calendar


def xcdat_open(
infile: Union[str, list], data_var: str = None, decode_times: bool = True
infile: Union[str, list], data_var: str = None, decode_times: bool = True, chunks={}
) -> xr.Dataset:
"""
Open input file (netCDF, or xml generated by cdscan)
Expand All @@ -24,6 +26,8 @@ def xcdat_open(
decode_times : bool, optional
If True, attempt to decode times encoded in the standard NetCDF datetime format into cftime.datetime objects.
Otherwise, leave them encoded as numbers. This keyword may not be supported by all the backends, by default True.
chunks : int, "auto", dict, or None, optional
The chunk size used to load data into dask arrays.
Returns
-------
Expand All @@ -45,16 +49,67 @@ def xcdat_open(
>>> ds = xcdat_open('mydata.xml')
"""
if isinstance(infile, list) or "*" in infile:
ds = xc.open_mfdataset(infile, data_var=data_var, decode_times=decode_times)
try:
ds = xc.open_mfdataset(
infile, data_var=data_var, decode_times=decode_times, chunks=chunks
)
except (
ValueError
): # Could be due to non-cf-compliant calendar or other attribute
ds = xc.open_mfdataset(
infile, data_var=data_var, decode_times=False, chunks=chunks
)
ds = fix_noncompliant_attr(ds)
else:
if infile.split(".")[-1].lower() == "xml":
ds = _xcdat_openxml(infile, data_var=data_var, decode_times=decode_times)
try:
ds = _xcdat_openxml(
infile, data_var=data_var, decode_times=decode_times, chunks=chunks
)
except (
ValueError
): # Could be due to non-cf-compliant calendar or other attribute
ds = _xcdat_openxml(
infile, data_var=data_var, decode_times=False, chunks=chunks
)
ds = fix_noncompliant_attr(ds)
else:
ds = xc.open_dataset(infile, data_var=data_var, decode_times=decode_times)
try:
ds = xc.open_dataset(
infile, data_var=data_var, decode_times=decode_times, chunks=chunks
)
except (
ValueError
): # Could be due to non-cf-compliant calendar or other attribute
ds = xc.open_dataset(
infile, data_var=data_var, decode_times=False, chunks=chunks
)
ds = fix_noncompliant_attr(ds)

return ds.bounds.add_missing_bounds()


def fix_noncompliant_attr(ds: xr.Dataset) -> xr.Dataset:
"""Fix dataset attributes that do not meet cf standards
Parameters
----------
ds: xr.Dataset
xarray dataset to fix
Returns
-------
xr.Dataset
xarray dataset with updated attributes
"""
# Add any calendar fixes here
cal = get_calendar(ds)
cal = cal.replace("-", "_")
ds.time.attrs["calendar"] = cal
ds = xc.decode_time(ds)
return ds


def _xcdat_openxml(
xmlfile: str, data_var: str = None, decode_times: bool = True
) -> xr.Dataset:
Expand Down
2 changes: 1 addition & 1 deletion pcmdi_metrics/variability_mode/lib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@
variability_metrics_to_json,
write_nc_output,
)
from .plot_map import plot_map # noqa
from .plot_map import plot_map, plot_map_multi_panel # noqa
from .north_test import north_test
14 changes: 14 additions & 0 deletions pcmdi_metrics/variability_mode/lib/eof_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,14 @@ def eof_analysis_get_variance_mode(
pc_Nth *= -1.0

# Supplement NetCDF attributes
eof_Nth.attrs["variable"] = data_var
eof_Nth.attrs["eof_mode"] = n + 1
frac_Nth.attrs["units"] = "ratio"
pc_Nth.attrs[
"comment"
] = f"Non-scaled time series for principal component of {eofn}th variance mode"
pc_Nth.attrs["variable"] = data_var
pc_Nth.attrs["eof_mode"] = n + 1

# append to lists for returning
eof_list.append(eof_Nth)
Expand Down Expand Up @@ -258,6 +262,14 @@ def linear_regression_on_globe_for_teleconnection(

eof_lr = (slope * factor) + intercept

eof_lr.attrs["variable"] = data_var
eof_lr.attrs["description"] = "linear regression on global field for teleconnection"
eof_lr.attrs[
"comment"
] = "Reconstructed EOF pattern with teleconnection considerations"
if "eof_mode" in pc.attrs:
eof_lr.attrs["eof_mode"] = pc.attrs["eof_mode"]

debug_print("linear regression done", debug)

return eof_lr, slope, intercept
Expand Down Expand Up @@ -346,10 +358,12 @@ def gain_pseudo_pcs(
pseudo_pcs = solver.projectField(
field_to_be_projected, neofs=eofn, eofscaling=0
)
pseudo_pcs.attrs["comment"] = "Non-scaled pseudo principal components"
else:
pseudo_pcs = solver.projectField(
field_to_be_projected, neofs=eofn, eofscaling=1
)
pseudo_pcs.attrs["comment"] = "Scaled pseudo principal components"
# Get CBF PC (pseudo pcs in the code) for given eofs
pseudo_pcs = pseudo_pcs[:, eofn - 1]
# Arbitrary sign control, attempt to make all plots have the same sign
Expand Down
21 changes: 20 additions & 1 deletion pcmdi_metrics/variability_mode/lib/lib_variability_mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ def tree():
return defaultdict(tree)


def write_nc_output(output_file_name, eofMap, pc, frac, slopeMap, interceptMap):
def write_nc_output(
output_file_name, eofMap, pc, frac, slopeMap, interceptMap, identifier=None
):
# Create a dataset
ds = xr.Dataset(
{
Expand All @@ -46,6 +48,23 @@ def write_nc_output(output_file_name, eofMap, pc, frac, slopeMap, interceptMap):
), # single number having no axis
}
)
# Add global attributes
ds.attrs[
"title"
] = "PCMDI Metrics Package Extratropical Modes of Variability diagnostics"
ds.attrs["author"] = "PCMDI"
ds.attrs["contact"] = "[email protected]"
ds.attrs["creation_date"] = strftime("%Y-%m-%d %H:%M:%S", gmtime())
ds.attrs[
"references"
] = """
Lee, J., K. Sperber, P. Gleckler, C. Bonfils, and K. Taylor, 2019: Quantifying the Agreement Between Observed and Simulated Extratropical Modes of Interannual Variability. Climate Dynamics, 52, 4057-4089, doi: 10.1007/s00382-018-4355-4,
Lee, J., K. Sperber, P. Gleckler, K. Taylor, and C. Bonfils, 2021: Benchmarking performance changes in the simulation of extratropical modes of variability across CMIP generations. Journal of Climate, 34, 6945–6969, doi: 10.1175/JCLI-D-20-0832.1,
Lee, J., P. J. Gleckler, M.-S. Ahn, A. Ordonez, P. Ullrich, K. R. Sperber, K. E. Taylor, Y. Y. Planton, E. Guilyardi, P. Durack, C. Bonfils, M. D. Zelinka, L.-W. Chao, B. Dong, C. Doutriaux, C. Zhang, T. Vo, J. Boutte, M. F. Wehner, A. G. Pendergrass, D. Kim, Z. Xue, A. T. Wittenberg, and J. Krasting, 2024: Systematic and Objective Evaluation of Earth System Models: PCMDI Metrics Package (PMP) version 3. Geoscientific Model Development, 17, 3919–3948, doi: 10.5194/gmd-17-3919-2024
"""
if identifier is not None:
ds.attrs["identifier"] = identifier
# Save the dataset to a netcdf file
ds.to_netcdf(output_file_name + ".nc")
ds.close()

Expand Down
Loading

0 comments on commit ee00de6

Please sign in to comment.