Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion e3sm_to_cmip/cmor_handlers/_formulas.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,20 +466,49 @@ def pr(ds: xr.Dataset) -> xr.DataArray:

High frequency version:
pr = PRECT * 1000.0

EAMxx version:
pr = precip_liq_surf_mass_flux + precip_ice_surf_mass_flux
or:
pr = precip_total_surf_mass_flux
"""
if all(key in ds.data_vars for key in ["PRECC", "PRECL"]):
result = (ds["PRECC"] + ds["PRECL"]) * 1000.0
elif "PRECT" in ds:
result = ds["PRECT"] * 1000.0
elif all(
key in ds.data_vars
for key in ["precip_liq_surf_mass_flux", "precip_ice_surf_mass_flux"]
):
result = ds["precip_liq_surf_mass_flux"] + ds["precip_ice_surf_mass_flux"]
elif "precip_total_surf_mass_flux" in ds:
result = ds["precip_total_surf_mass_flux"]
else:
raise KeyError(
"No formula could be applied for 'pr'. Check the handler entry for 'pr' "
"and input file(s) contain either 'PRECC' and 'PRECL', or 'PRECT."
"and input file(s) contain either 'PRECC' and 'PRECL', 'PRECT', "
"'precip_liq_surf_mass_flux' and 'precip_ice_surf_mass_flux', "
"or 'precip_total_surf_mass_flux'."
)

return result


def clwvi(ds: xr.Dataset) -> xr.DataArray:
"""
CMIP6 clwvi = condensed water path (liquid + ice).

EAM version:
clwvi = TGCLDCWP (total condensed = liquid + ice, single variable)

EAMxx version:
clwvi = LiqWaterPath + IceWaterPath
In EAMxx, LiqWaterPath is liquid-only and IceWaterPath is ice-only;
they must be summed to match the CMIP6 definition.
"""
return ds["LiqWaterPath"] + ds["IceWaterPath"]


def prsn(ds: xr.Dataset) -> xr.DataArray:
"""
prsn = (PRECSC + PRECSL) * 1000.0
Expand Down
277 changes: 277 additions & 0 deletions e3sm_to_cmip/cmor_handlers/handlers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1040,3 +1040,280 @@
formula: null
positive: null
levels: { name: plev19, units: Pa, e3sm_axis_name: plev }
# ============================================================
# EAMxx variable handlers (issue #339)
# Maps EAMxx output variable names to CMIP6 variables.
# These entries coexist with EAM entries above; the handler
# system selects whichever raw_variables are present in input.
# ============================================================
# --- Precipitation and column water ---
- name: pr
units: kg m-2 s-1
raw_variables: [precip_liq_surf_mass_flux, precip_ice_surf_mass_flux]
table: CMIP6_Amon.json
unit_conversion: null
formula: precip_liq_surf_mass_flux + precip_ice_surf_mass_flux
positive: null
levels: null
- name: prw
units: kg m-2
raw_variables: [VapWaterPath]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: null
levels: null
# --- Surface temperature and humidity ---
- name: ts
units: K
raw_variables: [surf_radiative_T]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: null
levels: null
- name: tas
units: K
raw_variables: [T_2m]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: null
levels: null
- name: huss
units: "1"
raw_variables: [qv_2m]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: null
levels: null
# --- Surface energy and momentum fluxes ---
- name: hfls
units: W m-2
raw_variables: [surface_upward_latent_heat_flux]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: up
levels: null
- name: hfss
units: W m-2
raw_variables: [surf_sens_flux]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: up
levels: null
- name: evspsbl
units: kg m-2 s-1
raw_variables: [surf_evap]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: null
levels: null
- name: tauu
units: Pa
raw_variables: [surf_mom_flux_U]
table: CMIP6_Amon.json
unit_conversion: "-1"
formula: null
positive: down
levels: null
- name: tauv
units: Pa
raw_variables: [surf_mom_flux_V]
table: CMIP6_Amon.json
unit_conversion: "-1"
formula: null
positive: down
levels: null
# --- 10m wind speed ---
- name: sfcWind
units: m s-1
raw_variables: [wind_speed_10m]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: null
levels: null
# --- Sea-level pressure ---
- name: psl
units: Pa
raw_variables: [SeaLevelPressure]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: null
levels: null
# --- TOA radiation ---
- name: rsdt
units: W m-2
raw_variables: [SW_flux_dn_at_model_top]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: down
levels: null
- name: rsut
units: W m-2
raw_variables: [SW_flux_up_at_model_top]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: up
levels: null
- name: rsutcs
units: W m-2
raw_variables: [SW_clrsky_flux_up_at_model_top]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: up
levels: null
- name: rlut
units: W m-2
raw_variables: [LW_flux_up_at_model_top]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: up
levels: null
- name: rlutcs
units: W m-2
raw_variables: [LW_clrsky_flux_up_at_model_top]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: up
levels: null
# --- Surface radiation ---
- name: rsds
units: W m-2
raw_variables: [SW_flux_dn_at_model_bot]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: down
levels: null
- name: rsus
units: W m-2
raw_variables: [SW_flux_up_at_model_bot]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: up
levels: null
- name: rsdscs
units: W m-2
raw_variables: [SW_clrsky_flux_dn_at_model_bot]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: down
levels: null
- name: rsuscs
units: W m-2
raw_variables: [SW_clrsky_flux_up_at_model_bot]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: up
levels: null
- name: rlds
units: W m-2
raw_variables: [LW_flux_dn_at_model_bot]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: down
levels: null
- name: rlus
units: W m-2
raw_variables: [LW_flux_up_at_model_bot]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: up
levels: null
- name: rldscs
units: W m-2
raw_variables: [LW_clrsky_flux_dn_at_model_bot]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: down
levels: null
# --- Cloud water paths ---
# CMIP6 clwvi = "condensed water path" = liquid + ice (per CMIP6_Amon.json comment).
# In EAMxx, LiqWaterPath is liquid-only (equiv. EAM TGCLDLWP), and
# IceWaterPath is ice-only (equiv. EAM TGCLDIWP). Their sum gives the
# total condensed water path required by CMIP6 clwvi.
# By contrast, EAM uses TGCLDCWP (total = liquid + ice) directly for clwvi.
- name: clwvi
units: kg m-2
raw_variables: [LiqWaterPath, IceWaterPath]
table: CMIP6_Amon.json
unit_conversion: null
formula: LiqWaterPath + IceWaterPath
positive: null
levels: null
- name: clivi
units: kg m-2
raw_variables: [IceWaterPath]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: null
levels: null
# --- Aerosol optical depth ---
- name: od550aer
units: "1"
raw_variables: [AerosolOpticalDepth550nm]
table: CMIP6_AERmon.json
unit_conversion: null
formula: null
positive: null
levels: null
# --- 3D pressure-level variables (requires data interpolated to plev) ---
- name: ta
units: K
raw_variables: [T_mid]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: null
levels: { name: plev19, units: Pa, e3sm_axis_name: plev }
- name: hus
units: "1"
raw_variables: [qv]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: null
levels: { name: plev19, units: Pa, e3sm_axis_name: plev }
- name: hur
units: "%"
raw_variables: [RelativeHumidity]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: null
levels: { name: plev19, units: Pa, e3sm_axis_name: plev }
- name: wap
units: Pa s-1
raw_variables: [omega]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: null
levels: { name: plev19, units: Pa, e3sm_axis_name: plev }
- name: zg
units: m
raw_variables: [z_mid]
table: CMIP6_Amon.json
unit_conversion: null
formula: null
positive: null
levels: { name: plev19, units: Pa, e3sm_axis_name: plev }
25 changes: 11 additions & 14 deletions e3sm_to_cmip/cmor_handlers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from importlib.machinery import SourceFileLoader
from typing import Any, Literal, get_args

import pandas as pd
import yaml

from e3sm_to_cmip import (
Expand Down Expand Up @@ -256,23 +255,21 @@ def _get_handlers_from_yaml() -> dict[str, list[dict[str, Any]]]:
with open(HANDLER_DEFINITIONS_PATH, "r") as infile:
handlers_file = yaml.load(infile, yaml.SafeLoader)

df_in = pd.DataFrame.from_dict(handlers_file)

handlers = defaultdict(list)
for row in df_in.itertuples():
for entry in handlers_file:
var_handler = VarHandler(
name=row.name, # type: ignore
units=row.units, # type: ignore
raw_variables=row.raw_variables, # type: ignore
table=row.table, # type: ignore
formula=row.formula, # type: ignore
unit_conversion=row.unit_conversion, # type: ignore
positive=row.positive, # type: ignore
levels=row.levels, # type: ignore
name=entry["name"],
units=entry["units"],
raw_variables=entry["raw_variables"],
table=entry["table"],
formula=entry.get("formula"),
unit_conversion=entry.get("unit_conversion"),
positive=entry.get("positive"),
levels=entry.get("levels"),
).to_dict()
handlers[row.name].append(var_handler)
handlers[entry["name"]].append(var_handler)

return dict(handlers) # type: ignore
return dict(handlers)


def _get_handlers_from_modules(path: str) -> dict[str, list[dict[str, Any]]]:
Expand Down
Loading
Loading