-
Notifications
You must be signed in to change notification settings - Fork 3
Add direct pint/pint-xarray support #41
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
Conversation
@rcaneill some early architecture discussion would be welcome. My thoughts so far:
p.s. COVID willing, I head to sea in about 3 weeks for ~2mo. |
I agree with this
Hm this is a good question. As the package is called gsw-xarray it makes sense that the users will have xarray installed, so having also pint-xarray would make sense to me. Indeed it would be nice that gsw could consume pint.Quantity inputs, but this is not the aim of our package.
Sounds good to me |
I guess that we will need to write a long dict of the units of the inputs of the gsw functions, to be able to convert the pint inputs (e.g. Pascal to bar, etc) I can probably modify the script in #28 to get this done |
I think that this PR would be ready to be merged. When merged I can start working on a new PR to check / convert the units of the arguments to match the needed units of the upstream gsw |
Feel free to merge, I don't remember the state it was in when I left for my cruise... so more tests in a follow up would be welcome. |
I will continue the work from this branch (add some more tests, play a little with pint, etc) before merging |
pre-commit = "^2.17.0" | ||
|
||
[tool.poetry.extras] | ||
docs = ["Sphinx", "furo"] | ||
pint = ["Pint", "pint-xarray"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me
@DocOtak can you review? I added support for pint only quantities, corrected a bug, and added few tests. I think that it is ready for merge, and it solves the issue: "If input is pint.Quantity or xarray.DataArray pint-xarray wrapped quantity, returns a quantity". Next step (in a next PR) would be "if input is quantity, verify / convert unit" |
I didn't get though looking at all this before the rosette came up and it was time to sample. I hope I can finish it tomorrow. |
No rush :) |
I just thought that we should be careful with the unit registry. If we return quantities that belong to another registry as the one the user had, things won't work (cf bottom of page https://pint.readthedocs.io/en/stable/tutorial.html). |
I'd like to ping @dcherian for advise on how best to handle pint unit registries. But I think what we'll want to do is call Seems my dev environment for this project is broken and I'm not sure I have the bandwidth to fix it out here (will make an attempt). |
I defer to @keewis for these questions :) You could consider adding cf_xarray as a dependency for unit handling. One of its intended goals is to provide a unit registry that works for CF-type things in the xarray world. It also has no extra dependencies. |
I think that adding cf_xarray for handling units is a reasonable choice. However, I don't think that this would solve the problem that we need to return quantities using the same registry than the one used by the quantities passed by the user. Correct me if I'm wrong, but cf_xarray would be needed only in the case where we would like to parse the units from input dataarrays? And if the user is using the cf_xarray unit registry, it should be caught by my previous point (using pint.get_application_registry() or other solution) |
Is there any way to inspect a Quantity (or Unit) and get the registry it belongs to? Nothing is jumping out at me in the pint docs regarding this. |
I've read though the source a little, and it looks like the ApplicationRegistry object that is returned by I think the only change needed is to swap the >>> import pint
>>> reg = pint.get_application_registry()
>>> reg("degree_north")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/vscode/.cache/pypoetry/virtualenvs/gsw-xarray-Apk1CQ_8-py3.8/lib/python3.8/site-packages/pint/registry.py", line 2425, in __call__
return self._registry(*args, **kwargs)
File "/home/vscode/.cache/pypoetry/virtualenvs/gsw-xarray-Apk1CQ_8-py3.8/lib/python3.8/site-packages/pint/registry.py", line 2372, in __call__
return self(*args, **kwargs)
File "/home/vscode/.cache/pypoetry/virtualenvs/gsw-xarray-Apk1CQ_8-py3.8/lib/python3.8/site-packages/pint/registry.py", line 1388, in parse_expression
return build_eval_tree(gen).evaluate(
File "/home/vscode/.cache/pypoetry/virtualenvs/gsw-xarray-Apk1CQ_8-py3.8/lib/python3.8/site-packages/pint/pint_eval.py", line 122, in evaluate
return define_op(self.left)
File "/home/vscode/.cache/pypoetry/virtualenvs/gsw-xarray-Apk1CQ_8-py3.8/lib/python3.8/site-packages/pint/registry.py", line 1389, in <lambda>
lambda x: self._eval_token(x, case_sensitive=case_sensitive, **values)
File "/home/vscode/.cache/pypoetry/virtualenvs/gsw-xarray-Apk1CQ_8-py3.8/lib/python3.8/site-packages/pint/registry.py", line 1275, in _eval_token
{self.get_name(token_text, case_sensitive=case_sensitive): 1}
File "/home/vscode/.cache/pypoetry/virtualenvs/gsw-xarray-Apk1CQ_8-py3.8/lib/python3.8/site-packages/pint/registry.py", line 722, in get_name
raise UndefinedUnitError(name_or_alias)
pint.errors.UndefinedUnitError: 'degree_north' is not defined in the unit registry
>>> from cf_xarray import units
/home/vscode/.cache/pypoetry/virtualenvs/gsw-xarray-Apk1CQ_8-py3.8/lib/python3.8/site-packages/cf_xarray/units.py:114: UserWarning: Import(s) unavailable to set up matplotlib support...skipping this portion of the setup.
warnings.warn(
>>> reg("degree_north")
<Quantity(1, 'degrees_north')> |
Seems good but if the user has multiple registries, and uses the 1st one for the quantities, then using get_application_registry will return the 2nd registry I guess. Maybe having a look at the # Registry equality check based on util.SharedRegistryObject
if self._REGISTRY is not other._REGISTRY:
mess = "Cannot operate with {} and {} of different registries."
raise ValueError(
mess.format(self.__class__.__name__, other.__class__.__name__)
)` |
Hum, looking more in details in the sources, it feels like the _REGISTRY is pointing to the same thing as the get_application_registry... |
So maybe instead of creating / loading the registry, we could: 1) verify that all inputs belong to the same registry in our If no one tries / tests this (European) night, I may give it a try tomorrow if I have time. |
this is what For 2: |
@rcaneill managed to get my dev env back up and running! I made an attempt to implement what's been discussed here:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing! Thanks Andrew :)
For what I see it seems ready to merge
Let me write some docs as the final touch. Do we want to attempt some unit input validation in this dev cycle (in a separate PR). e.g. make sure the SA input is g/kg? |
I started this, I open a PR with my (very early) WIP so we can discuss API and choices: see PR #47. |
Does the readme make sense? Are more docs needed? (@rcaneill merge if you think it's good) |
This is very clear! |
Aims to add support for setting the correct units on inputs that are either pint.Quantities or wrappers of pint.Quantities such as xarray (and the very handy pint-xarray library).
This is a work in progress as the API needs get figured out a bit.