yt-project / unyt

Handle, manipulate, and convert data with units in Python
https://unyt.readthedocs.io
BSD 3-Clause "New" or "Revised" License
364 stars 48 forks source link

Bug: u.amu != u.g/u.mol #417

Closed daico007 closed 1 year ago

daico007 commented 1 year ago

Description

My collaborator (@chrisjonesBSU) and I bump into this weird issue when we try to handle atomic mass unit (amu), specifically when we try to compare it with equivalent mass unit.

What I Did

import unyt as u 

amu = 1 * u.amu 
gmol = 1 * u.g/u.mol

amu == gmol # --> This will be False 

# Next I tried to convert it to a common unit for comparison
amu = amu.to(u.kg)
gmol = gmol.to(u.kg) 

# The value for both is 
# unyt_quantity(1.66053892e-27, 'kg')
# but 

amu == gmol # --> This is still False
ngoldbaum commented 1 year ago

This is because of a floating point precision issue:

In [1]: import unyt as u

In [2]: amu = 1 * u.amu
   ...: gmol = 1 * u.g/u.mol

In [3]: import numpy as np

In [4]: np.set_printoptions(precision=25)

In [5]: amu.to('kg')
Out[5]: unyt_quantity(1.660538921e-27, 'kg')

In [6]: gmol.to('kg')
Out[6]: unyt_quantity(1.6605389210000002e-27, 'kg')

In general there's not a ton we can do about this sort of thing without doing unit conversions in extended precision. In principle that's something we could do, but it would have impacts on performance that would need to be looked at.

Also note that after 2019, the SI system does not guarantee the atomic mass unit to be exactly 1 g/mol, since avogadro's number was redefined to be exactly 6.02214076*10**23. Now, we haven't updated our unit definitions to reflect that so in principle the way these units are defined you should get the identity you expect to be correct, but as explained above floating point round-off error prevents that from happening exactly.

daico007 commented 1 year ago

Got it, thank you!