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 kelvin instead if Kelvin for units #544

Open
aaschwanden opened this issue Apr 24, 2024 · 4 comments
Open

Consider using kelvin instead if Kelvin for units #544

aaschwanden opened this issue Apr 24, 2024 · 4 comments

Comments

@aaschwanden
Copy link
Member

Description

cf_xarray.units which implements CF conforming units, has Celsius, but not Kelvin. Switching PISM's default from Kelvin to kelvin would allow seamless use of Xarray in combination with pint_xarray and cf_xarray.

PISM version

PISMR (basic evolution run mode) 2.1.99-d7dc90a06

To Reproduce

In a shell:

pismr -EisII A -o_size big_2d -o pism_test_pint_xarray.nc
pip install xarray cf_xarray pint_xarray

In python:

import xarray as xr
import cf_xarray.units
import pint_xarray
ds = xr.open_dataset("pism_test_pint_xarray.nc")
for v in ds.data_vars:
    da = ds[v]
    da.pint.quantify()

ValueError: Cannot parse units:
    invalid units for variable 'shelfbtemp': Kelvin (attribute) (reason: 'Kelvin' is not defined in the unit registry)

@aaschwanden aaschwanden changed the title Consider using kelvin instead if 'Kelvin` Consider using kelvin instead if Kelvin for units Apr 24, 2024
@ckhroulev
Copy link
Member

No objections. Note that NIST spells kelvin with a lower case k and UDUNITS supports both "kelvin" and "Kelvin" (and degree_Kelvin, which, according to NIST, is wrong).

We should probably also replace "K" with "kelvin" in unit strings, for consistency (pint does recognize "K" as "kelvin", though.)

Another compatibility issue: UDUNITS parses m s-2 as "m/s^2", i.e. a unit followed by an integer is interpreted as unit raised to a power. We should replace m s-2 with m s^-2 and so on. (UDUNITS recognizes m2, m^2 and m**2, so this would not break anything. pint recognizes m^2, m**2, m^-2, etc, but not m-2.)

We should also replace "Celsius" with degC or degree_Celsius since pint does supports the latter two and not the first one.

PS: UDUNITS appears to be case-insensitive.

@ckhroulev ckhroulev self-assigned this Apr 24, 2024
ckhroulev added a commit that referenced this issue Apr 24, 2024
Replacements:
- "Kelvin"  -> "kelvin"
- "K"       -> "kelvin"
- "Celsius" -> "degree_Celsius"
ckhroulev added a commit that referenced this issue Apr 24, 2024
(See http://pint.readthedocs.org/ and #544.)

Replace "kg m-2 year-1" with "kg m^-2 year^-1" and so on.

Also: "Kelvin" -> "kelvin" throughout and replace "degree kelvin" -> "kelvin".
@ckhroulev
Copy link
Member

The modified test script

import xarray as xr
import cf_xarray.units
import pint_xarray
import sys
ds = xr.open_dataset(sys.argv[1])

for v in ds.data_vars:
    if v == "hardav":
        continue
    print(da.pint.quantify())

works with PISM from the dev branch.

The "hardav" variable has units pascal * second ^ (1/n) where n is the Glen exponent.

Fractional powers are not supported by UDUNITS, so I'm not sure what to do about that. Setting units to Pa s^0.333 or similar confuses UDUNITS because it interprets it as Pa s^0 * 333 = 333 Pa, while Pa s^(1/3) is not a valid UDUNITS string (but is a valid string according to pint.)

@aaschwanden
Copy link
Member Author

aaschwanden commented Apr 25, 2024 via email

@ckhroulev
Copy link
Member

@aaschwanden CF conventions allow most units supported by UDUNITS (with some exceptions), so degree_Celsius is OK.

The value of the units attribute is a string that can be recognized by the UDUNITS package [UDUNITS], with the exceptions that are given in Section 3.1.1, "Dimensionless units" and Section 3.1.3, "Scale factors and offsets". Note that case is significant in the units strings.

(See section 3.1. Units for more.)

This works:

$ echo -e "degree_Celsius\nkelvin" | udunits2 
You have: You want:     1 degree_Celsius = 274.15 kelvin
    x/kelvin = (x/degree_Celsius) + 273.15
You have:

And this works too, so I think we're okay here.

$ python -c "import pint; print(pint.Unit('degree_Celsius'))"
degree_Celsius

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants