Skip to content

Commit

Permalink
Add alternate standard names entry to fieldlists and varlistEntry obj…
Browse files Browse the repository at this point in the history
…ects (#699)

* add alternate_stanadard_names entries to precipitation_flux vars in CMIP and GFDL fieldlists
add list of applicable realms to preciptitation flux

* add alternate_standard_names attributes and property setters to DMDependentvariable class that is VarlistEntry parent class
define realm parm as string or list

* extend realm search in fieldlist lookup tables to use a realm list in the translation
add list to realm type hints in translation module

* extend standard_name query to list that includes alternate_standard_names if present in the translation object

* break up rainfall_flux and precipitation_flux entries in CMIP and GFDL field tables since translator can't parse realm list correctly

* revert realm type hints defined  as string or list and casting realm strings to listsin translation module

* change assertion to log errof if translation is None in varlist_util

* define new standard_name for pp xarray vars using the translation standard_name if the query standard name is a list with alternates instead of a string
  • Loading branch information
wrongkindofdoctor authored Oct 25, 2024
1 parent 25671db commit a383592
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 29 deletions.
8 changes: 8 additions & 0 deletions data/fieldlist_CMIP.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,14 @@
"standard_name": "precipitation_flux",
"realm": "atmos",
"units": "kg m-2 s-1",
"alternate_standard_names": ["rainfall_flux"],
"ndim": 3
},
"rainfall_flux": {
"standard_name": "rainfall_flux",
"realm": "seaIce",
"units": "kg m-2 s-1",
"alternate_standard_names": ["precipitation_flux"],
"ndim": 3
},
"prc": {
Expand Down
25 changes: 8 additions & 17 deletions data/fieldlist_GFDL.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -186,28 +186,19 @@
"scalar_coord_templates": {"plev": "omega{value}"},
"ndim": 4
},
// NOTE: pr is the same for sea Ice and ocean realms, and there are duplicate entries;
// TODO: refine realm entry parsing in framework to allow lists and strings
"pr": {
"standard_name": "rainfall_flux",
"long_name": "Surface Rainfall Rate into the Sea Ice Portion of the Grid Cell",
"realm": "seaIce",
"units": "kg m-2 s-1",
"ndim": 3
},
"pr": {
"standard_name": "rainfall_flux",
"long_name": "Surface Rainfall Rate into the Sea Ice Portion of the Grid Cell",
"realm": "ocean",
"units": "kg m-2 s-1",
"ndim": 3
},

"precip": {
"standard_name": "precipitation_flux",
"long_name":"",
"realm": "atmos",
"units": "kg m-2 s-1",
"alternate_standard_names": ["rainfall_flux"],
"ndim": 3
},
"rainfall_flux": {
"standard_name": "rainfall_flux",
"realm": "seaIce",
"units": "kg m-2 s-1",
"alternate_standard_names": ["precipitation_flux"],
"ndim": 3
},
"prec_conv": {
Expand Down
17 changes: 16 additions & 1 deletion src/data_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ def long_name(self):
"""
pass

@property
@abc.abstractmethod
def alternate_standard_names(self):
"""Optional list of alternate variable standard_names to query"""
pass


class AbstractDMCoordinateBounds(AbstractDMDependentVariable):
"""Defines interface (set of attributes) for :class:`DMCoordinateBounds`
Expand Down Expand Up @@ -764,6 +770,7 @@ class DMDependentVariable(_DMDimensionsMixin, AbstractDMDependentVariable):
component: str = ""
associated_files: str = ""
rename_coords: bool = True
alternate_standard_names: list

# dims: from _DMDimensionsMixin
# scalar_coords: from _DMDimensionsMixin
Expand Down Expand Up @@ -860,9 +867,17 @@ def realm(self):
return self._realm

@realm.setter
def realm(self, value: str):
def realm(self, value: str | list):
self._realm = value

@property
def alternate_standard_names(self):
return self._alternate_standard_names

@alternate_standard_names.setter
def alternate_standard_names(self, value: list):
self._alternate_standard_names = value

def add_scalar(self, ax, ax_value, **kwargs):
"""Metadata operation corresponding to taking a slice of a higher-dimensional
variable (extracting its values at axis *ax* = *ax_value*). The
Expand Down
9 changes: 8 additions & 1 deletion src/preprocessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,8 @@ def query_catalog(self,
if var.translation.convention is not None:
var_id = var.translation.name
standard_name = var.translation.standard_name
if any(var.translation.alternate_standard_names):
standard_name = [var.translation.standard_name] + var.translation.alternate_standard_names
date_range = var.translation.T.range
if var.is_static:
date_range = None
Expand Down Expand Up @@ -1050,7 +1052,12 @@ def query_catalog(self,
for vname in var_xr.variables:
if (not isinstance(var_xr.variables[vname], xr.IndexVariable)
and var_xr[vname].attrs.get('standard_name', None) is None):
var_xr[vname].attrs['standard_name'] = case_d.query.get('standard_name')
case_query_standard_name = case_d.query.get('standard_name')
if isinstance(case_query_standard_name, list):
new_standard_name = [name for name in case_query_standard_name if name == var.translation.standard_name][0]
else:
new_standard_name = case_query_standard_name
var_xr[vname].attrs['standard_name'] = new_standard_name
var_xr[vname].attrs['name'] = vname
if case_name not in cat_dict:
cat_dict[case_name] = var_xr
Expand Down
20 changes: 11 additions & 9 deletions src/translation.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ def _process_var(section_name: str, in_dict, lut_dict):
lut_dict['entries'][k].update({'long_name': ""})
if 'scalar_coord_templates' in v:
sct_dict.update({k: v['scalar_coord_templates']})
if 'alternate_standard_names' not in v:
lut_dict['entries'][k].update({'alternate_standard_names': list()})
return lut_dict, sct_dict

d['axes_lut'] = util.WormDict()
Expand Down Expand Up @@ -150,12 +152,13 @@ def to_CF_standard_name(self, standard_name: str,
precip_vars = ['precipitation_rate', 'precipitation_flux']
# search the lookup table for the variable with the specified standard_name
# realm, modifier, and long_name attributes

for var_name, var_dict in self.lut.items():
if var_dict['standard_name'] == standard_name\
if var_dict['standard_name'] == standard_name \
and var_dict['realm'] == realm\
and var_dict['modifier'] == modifier:
# if not var_dict['long_name'] or var_dict['long_name'].lower() == long_name.lower():
return var_name
return var_name
else:
if var_dict['standard_name'] in precip_vars and standard_name in precip_vars:
return var_name
Expand All @@ -176,7 +179,7 @@ def from_CF(self,
TODO: expand with more ways to uniquely identify variable (eg cell methods).
Args:
standard_name: variable or name of the variable
realm: variable realm (atmos, ocean, land, ice, etc...)
realm: str variable realm (atmos, ocean, land, seaIce, etc...)
modifier:optional string to distinguish a 3-D field from a 4-D field with
the same var_or_name value
long_name: str (optional) long name attribute of the variable
Expand Down Expand Up @@ -213,8 +216,8 @@ def from_CF_name(self,
convention.
Args:
var_or_name: variable or name of the variable
realm: model realm of variable
var_or_name: str, variable or name of the variable
realm: str model realm of variable
long_name: str (optional): long_name attribute of the variable
modifier:optional string to distinguish a 3-D field from a 4-D field with
the same var_or_name value
Expand Down Expand Up @@ -253,7 +256,7 @@ def create_scalar_name(self, old_coord, new_coord: dict, var_id: str, log=_log)
# construct convention's name for this variable on a level
name_template = self.scalar_coord_templates[var_id][key]
if new_coord.units.strip('').lower() == 'pa':
val = int(new_coord.value/100)
val = int(new_coord.value / 100)
else:
val = int(new_coord.value)

Expand Down Expand Up @@ -304,8 +307,8 @@ def translate_coord(self, coord, class_dict=None, log=_log) -> dict:
lut_val = v.get('value')
if isinstance(coord.value, int) and isinstance(lut_val, str):
v_int = int(float(lut_val))
if v_int > coord.value and v_int/coord.value == 100 \
or v_int < coord.value and coord.value/v_int == 100 or \
if v_int > coord.value and v_int / coord.value == 100 \
or v_int < coord.value and coord.value / v_int == 100 or \
v_int == coord.value:
new_coord = v
break
Expand Down Expand Up @@ -376,7 +379,6 @@ def translate(self, var, from_convention: str):
from_convention_tl = VariableTranslator().get_convention(from_convention)
# Fieldlist entry for POD variable
long_name = self.get_variable_long_name(var, has_scalar_coords)

fl_entries = from_convention_tl.from_CF(var.standard_name,
var.realm,
var.modifier,
Expand Down
3 changes: 2 additions & 1 deletion src/varlist_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -560,7 +560,8 @@ def setup_var(self,
v.dest_path = self.variable_dest_path(model_paths, case_name, v)
try:
trans_v = translate.translate(v, from_convention)
assert trans_v is not None, f'translation for varlistentry {v.name} failed'
if trans_v is None:
v.log.error(f'translation for varlistEntry {v.name} failed')
v.translation = trans_v
# copy preferred gfdl post-processing component during translation
if hasattr(trans_v, "component"):
Expand Down

0 comments on commit a383592

Please sign in to comment.