Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

consider using cf_xarray #12

Closed
dcherian opened this issue Mar 2, 2021 · 3 comments
Closed

consider using cf_xarray #12

dcherian opened this issue Mar 2, 2021 · 3 comments
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@dcherian
Copy link

dcherian commented Mar 2, 2021

I saw your tweet and this looks like a cool project.

cf_xarray should help you remove the CF parsing code, it's intended to allow indexing by standard_name etc. I'd be happy to consider changes that would make its use in this project easier.

@juseg
Copy link
Owner

juseg commented Mar 2, 2021

Thank you for passing by here and bringing this up! It seems like something I should be using indeed.

@juseg juseg self-assigned this Mar 2, 2021
@juseg juseg added the enhancement New feature or request label Mar 2, 2021
@juseg juseg added this to the v0.2.0 milestone Mar 2, 2021
@juseg juseg modified the milestones: v0.2.0, v0.1.2 Jul 26, 2022
@juseg
Copy link
Owner

juseg commented Jul 26, 2022

Closing this as done (for one year actually). Hyoga will use cf_xarray from the next release v0.1.2. However, the code still relies on internal method getvar for some heuristics, e.g. computing a vector magnitude from its components, or glacier surface altitude as bedrock altitude plus ice thickness.

hyoga/hyoga/hyoga.py

Lines 231 to 304 in 7e735f9

def getvar(self, standard_name, infer=True, directions=None):
"""Get a variable by conventional standard name.
Parameters
----------
standard_name : str
The variable's "standard_name" attribute, which in principle
should be set according to netCDF Climate and Forecast (CF)
conventions (http://cfconventions.org/standard-names.html).
infer : bool
Try to infer missing variables from others present in the dataset.
If one of the topographic variables ("bedrock_altitude",
"land_ice_thickness", and "surface_altitude") is requested and
missing from the data, try to compute it from the other two.
If a variable name starting with "magnitude_of" is requested and
missing, try to compute it as the norm of its components.
directions : iterable
Allowed direction keywords for computing vector magnitudes.
Defaults to ("upward", "downward", "x", "y"). Computing magnitudes
on a sphere is not supported and thus longitude and latitude
directions ("northward", "southward", "eastward", "westward")
are not included by default.
Returns
-------
array : DataArray
The data array corresponding to that variable if a unique variable
with that standard name has been found.
"""
# if variable is present, return it
if standard_name in self._ds.cf:
return self._ds.cf[standard_name]
# no variable found, try to compute it from other variables
if infer is True:
# try to get ice mask from ice thickness
# FIXME make threshold configurable
if standard_name == 'land_ice_area_fraction':
return (self.getvar('land_ice_thickness') > 0).astype(
float).assign_attrs(standard_name=standard_name)
# try to compute altitude and thickness variables
# (infer=False is needed to avoid infinite recursion)
if standard_name == 'bedrock_altitude':
return self._safe_sub(
'surface_altitude', 'land_ice_thickness', infer=False
).assign_attrs(standard_name=standard_name)
if standard_name == 'land_ice_thickness':
return self._safe_sub(
'surface_altitude', 'bedrock_altitude', infer=False
).assign_attrs(standard_name=standard_name)
if standard_name == 'surface_altitude':
return self._safe_sum(
'bedrock_altitude', 'land_ice_thickness', infer=False
).assign_attrs(standard_name=standard_name)
# try to get the magnitude of a vector from its components
if standard_name.startswith('magnitude_of_'):
vector = standard_name.replace('magnitude_of_', '', 1)
directions = directions or ('upward', 'downward', 'x', 'y')
components = [
var.attrs['standard_name'] for var in self._ds.values() if
vector in [
var.attrs.get('standard_name', '').replace('_'+d, '')
for d in directions]]
if len(components) > 0:
return self._safe_mag(*components).assign_attrs(
standard_name=standard_name)
# really nothing worked, give up
raise ValueError(
f"No variable found with standard name {standard_name}.")

@juseg juseg closed this as completed Jul 26, 2022
@dcherian
Copy link
Author

Good to hear!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants