bjodah / chempy

⚗ A package useful for chemistry written in Python
BSD 2-Clause "Simplified" License
536 stars 79 forks source link

[Feature] Significant Figures #189

Closed afshawnlotfi closed 3 years ago

afshawnlotfi commented 3 years ago

It would be nice if there was a feature for adding significant figures for numbers when adding units and all future calculations would take the sig figs into account.

bjodah commented 3 years ago

Agreed, the underlying library for dealing with units (i.e. quantities) does support uncertainties. I did start looking into this a while back, so there is some support for it scattered around in the code (you can try git grep -i uncertain). You can actually import the class UncertainQuantitiy from chempy.units:

In [3]: from chempy.units import UncertainQuantity

In [5]: UncertainQuantity(3.0, 'molar', 0.1)
Out[5]: UncertainQuantity(array(3.), M, array(0.1))

In [6]: c = UncertainQuantity(3.0, 'molar', 0.1)

In [7]: c*c
Out[7]: UncertainQuantity(array(9.), M**2, array(0.42426407))

In [8]: c-c
Out[8]: UncertainQuantity(array(0.), M, array(0.14142136))

In [9]: c+c
Out[9]: UncertainQuantity(array(6.), M, array(0.14142136))

In [10]: 2*c
Out[10]: UncertainQuantity(array(6.), M, array(0.2))

so quantities treats all uncertainties as normal distributions (with all limitations such a simplifcation implies). And for transcendental functions we would need to wrap e.g. numpy:

In [11]: from chempy.units import default_units as u
In [12]: from chempy.units import patched_numpy as pnp

In [13]: pnp.sin(c/u.molar)
Out[13]: UncertainQuantity(array(0.14112001), dimensionless, array(0.))

As you can see, we need to add support for uncertainties in patched_numpy, it shouldn't be too difficult. I guess evaluating the derivative of the function at the point of interest and scaling the uncertainty by this number would be a fair treatment.

Since Python is such a dynamic language you could probably support a non-native syntax¹ for input (some imaginary syntax below):

>>> from chempy.units import uncertainty_syntax
>>> uncertainty_syntax.install()
>>> (0.15 +/- 0.03)*u.molar
UncertainQuantity(array(0.15), M, array(0.03))

but that's a whole separate project in its own right.

afshawnlotfi commented 3 years ago

Oh wow awesome! I looked into quantities. Awesome stuff. I'll close this because this is technically supported I just didn't see too much documentation or issues in the past.