bp / resqpy

Python API for working with RESQML models
https://resqpy.readthedocs.io/en/latest/
MIT License
52 stars 13 forks source link

Support full set of RESQML units of measure #95

Closed connortann closed 3 years ago

connortann commented 3 years ago

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/

andy-beer commented 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.

connortann commented 3 years ago

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.

andy-beer commented 3 years ago

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!

connortann commented 3 years ago

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 π

connortann commented 3 years ago

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)
connortann commented 3 years ago

From our Teams chat, our priorities for functionality are:

  1. Identifying whether a unit is a valid uom
  2. Converting values between different valid units
  3. Coercing invalid units into equivalent valid uoms

A mental model of how Quantities, UoMs and Property kinds relate together:

image

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? 
}
connortann commented 3 years ago

Closed via #112