Closed connortann closed 3 years ago
No. I don't think we should go down the pint route.
RESQML has a very thorough and rigorous system of units of measure. It includes "volume per volume" and similar dimensionless quantity classes, with uoms such as "m3/m3" and "ft3/ft3". I think it will be too confusing to muddle together pint and RESQML uom systems.
If we are losing the uom for ratios in our workflows, we need to improve our code – but the fault will typically be in calling code rather than resqpy.
Having said that, resqpy does not currently make full use of RESQML's uom information and could be improved to do so.
I agree with you that we should use of RESQML units of measure, and it would be confusing to muddle together a different unit system. That's not what I was thinking though.
I think we may be misrepresenting pint here. Pint it is primarily a lightweight package for implementing a unit system, and also happens to come with a ready-made configuration for common units.
I was thinking we could use pint to implement the RESQML unit system behind the scenes in resqpy.
Ah yes, I've had a quick glance at the Pint documentation and think I see what you are suggesting @connortann. We could in principal provide a uom/pint build process which takes the RESQML uom related data and constructs the Pint definition file (to completely replace the default). RESQML does have an extra concept – quantity class – which sits between units and dimensions. However, I can't think of a need to have more than one quantity class for a given dimensionality, so the two systems should map onto each other quite cleanly. Let's discuss!
We can we also take the opportunity to ensure in the unit system we banish any ugly instances of π and ensure we're using the much more beautiful τ == 2 π
For future reference, here is the pseudo-code from our discussion on how calling code might work:
from pint import UnitRegistry
ureg = UnitRegistry('./resqpy_units.txt')
def parse_quantity(value, unit, property_kind):
"""Parse an input value into the resqml unit system"""
valid_uoms, default_uom = bwam.get_valid_uoms(property_kind)
if unit in valid_uoms:
resqml_value = value
resqml_uom = unit
else:
quantity = ureg.Quantity(value, unit).to(default_uom)
resqml_value = quantity.magnitude
resqml_uom = default_uom
return resqml_value, resqml_uom
class Property:
def init(self, value, unit):
quantity, valid_uom = parse_quantity(value, unit)
self.value = quantity
self.uom = valid_uom
def as_pint_quantity():
return ureg.Quantity(self.value, self.uom)
From our Teams chat, our priorities for functionality are:
A mental model of how Quantities, UoMs and Property kinds relate together:
And a schematic for how we may wish to represent this in JSON (which we wish to generate from the XSD):
# resqml_property_kinds.json
# RESQML specific
# Should be extendable
# Continuous property kinds only
{
property_kind name:
- Description
- Supported Quantity
- Example uom
}
# uoms.json
# Cannot be extended
# Common to PRODML, WITSML, RESQML
{
Quantities:
- Name
- base uom
- Dimension
uoms:
- Name
- Quanitiy(s)
- Conversion factor to base
- Base uom?
}
Closed via #112
Presently, common units such as "v/v" are lost and stored as "EUC".
A really exciting option could be to include pint, and include a short config file to handle the most common units used in reservoir modelling. This could be (hopefully) an elegant way to allow a wide range of common units, with simple configuration - and could be a "selling point" of resqpy more broadly.
https://pint.readthedocs.io/en/stable/