Skip to content

Commit

Permalink
Fix division float over scalar and float over array and add floor div…
Browse files Browse the repository at this point in the history
…ision support

BARRIL-15
  • Loading branch information
arthursoprana committed Oct 10, 2019
1 parent f9976a7 commit cf9e39d
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 11 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ UNRELEASED
* Add new unit category mass temperature per mol (``kg.K/mol``).
* Some units have been renamed as they were deemed out-of-place in the oil industry to something more usual (for example, ``1000ft3/d`` became ``Mcf/d``).
The old representation of those units is still supported, but they will be automatically translated during ``Quantity`` creation, so this change should not affect users much.
* Fix division ``1.0 / a`` where ``a`` is a ``Scalar`` or ``Array`` and also add support for floor
division, i.e., operations like ``a // b`` where ``a`` and ``b`` are ``Scalar`` or ``Array``
(and combinations with ``float`` or ``int``).

1.7.1 (2019-10-03)
------------------
Expand Down
11 changes: 10 additions & 1 deletion src/barril/units/_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
from oop_ext.interface._interface import ImplementsInterface

from ._abstractvaluewithquantity import AbstractValueWithQuantityObject
from .interfaces import IArray
from ._quantity import Quantity
from .interfaces import IArray

__all__ = ["Array"]

Expand Down Expand Up @@ -246,6 +246,9 @@ def __iter__(self):
def __truediv__(self, other):
return self._DoOperation(self, other, "Divide")

def __floordiv__(self, other):
return self._DoOperation(self, other, "FloorDivide")

def __mul__(self, other):
return self._DoOperation(self, other, "Multiply")

Expand All @@ -256,6 +259,12 @@ def __sub__(self, other):
return self._DoOperation(self, other, "Subtract")

# Right-Basic operators ------------------------------------------------------------------------
def __rtruediv__(self, other):
return self._DoOperation(other, self, "Divide")

def __rfloordiv__(self, other):
return self._DoOperation(other, self, "FloorDivide")

def __rdiv__(self, other):
return self._DoOperation(other, self, "Divide")

Expand Down
24 changes: 19 additions & 5 deletions src/barril/units/_scalar.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,8 @@ def __lt__(self, other):
def __rtruediv__(self, other):
return self._DoOperation(other, self, "Divide", lambda a, b: a / b)

__rfloordiv__ = __rtruediv__
def __rfloordiv__(self, other):
return self._DoOperation(other, self, "FloorDivide", lambda a, b: a // b)

def __rmul__(self, other):
return self._DoOperation(other, self, "Multiply", lambda a, b: a * b)
Expand All @@ -284,7 +285,8 @@ def __radd__(self, other):
def __truediv__(self, other):
return self._DoOperation(self, other, "Divide", lambda a, b: a / b)

__floordiv__ = __truediv__
def __floordiv__(self, other):
return self._DoOperation(self, other, "FloorDivide", lambda a, b: a // b)

def __mul__(self, other):
return self._DoOperation(self, other, "Multiply", lambda a, b: a * b)
Expand All @@ -302,7 +304,8 @@ def __pow__(self, exponent):
return result

def _DoOperation(self, p1, p2, operation, callback_operation):
if IsNumber(p1):
p1_is_number = IsNumber(p1)
if p1_is_number and operation not in ["Divide", "FloorDivide"]:
return self.__class__.CreateWithQuantity(
self._quantity, callback_operation(p1, self._value)
)
Expand All @@ -313,8 +316,19 @@ def _DoOperation(self, p1, p2, operation, callback_operation):
)

unit_database = self._unit_database
operation = getattr(unit_database, operation)
q, v = operation(p1.GetQuantity(), p2.GetQuantity(), self._value, p2.value)
operation_func = getattr(unit_database, operation)
if p1_is_number:
assert operation in [
"Divide",
"FloorDivide",
], "Only operation Divide and FloorDivide allowed here!"
q, v = operation_func(
Quantity.CreateEmpty(), p2.GetQuantity(), p1, p2.value
)
else:
q, v = operation_func(
p1.GetQuantity(), p2.GetQuantity(), self._value, p2.value
)
return self.__class__.CreateWithQuantity(q, v)

def __reduce__(self):
Expand Down
21 changes: 19 additions & 2 deletions src/barril/units/_tests/test_array.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import pytest
from pytest import approx

from collections import OrderedDict
from barril import units
from barril.units import Array, InvalidUnitError, ObtainQuantity, Quantity
from pytest import approx


def testEmptyArray():
Expand Down Expand Up @@ -215,6 +214,24 @@ def testDivision(unit_database_len_time):
assert calculated1 == s1 / s2


def testFloorDivision():
a = Array([3.5, 4.2], "m")
b = Array([100.0, 100.0], "cm")
assert approx((a // b).GetValues()) == [3.0, 4.0]
assert approx((350 // b).GetValues("1/cm")) == [3.0, 3.0]
assert approx((a // 1.0).GetValues("m")) == [3.0, 4.0]


def testNumberOverArray():
a = Array([2.0, 2.0], "m")
b = Array([3.0, 3.0], "m")
c = 1.0 / a

assert approx(c.GetValues("1/m")) == [0.5, 0.5]
assert approx((3.0 / a).GetValues("1/m")) == [1.5, 1.5]
assert b / a == b * 1 / a == b * (1 / a)


def testNumberInteractions(unit_database_len_time):
import numpy

Expand Down
3 changes: 3 additions & 0 deletions src/barril/units/_tests/test_derived_quantities.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ def testConvertionWithDerivedUnits(unit_database_len_time):
# check division with cancelling units (and different categories)
assert (empty, 1) == unit_database.Divide(m, m_city, 1, 1)

# floor division
assert (m, 3.0) == unit_database.FloorDivide(cat_mix_m2, km_city, 3.5, 0.001)

# sum
assert (m, 1 + 0.01) == unit_database.Sum(m, cm, 1, 1)
assert (m, 2) == unit_database.Sum(m, m_city, 1, 1)
Expand Down
21 changes: 18 additions & 3 deletions src/barril/units/_tests/test_scalar.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,17 @@
"""

import pytest
from pytest import approx

from collections import OrderedDict
from barril import units
from barril.units import (
ChangeScalars,
InvalidOperationError,
InvalidUnitError,
ObtainQuantity,
Quantity,
Scalar,
ChangeScalars,
)
from pytest import approx


def testScalarInterface(unit_database_well_length):
Expand Down Expand Up @@ -319,6 +318,22 @@ def testDivision(unit_database_len_time):
assert calculated1 == s1 / s2


def testFloorDivision():
a = Scalar(3.5, "m")
b = Scalar(100.0, "cm")
assert (a // b).GetValueAndUnit() == (3.0, "")
assert (350 // b).GetValueAndUnit() == (3.0, "1/cm")
assert (a // 1.0).GetValueAndUnit() == (3.0, "m")


def testNumberOverScalar():
a = Scalar(2.0, "m")
b = Scalar(3.0, "m")
assert (1.0 / a).GetValueAndUnit() == (0.5, "1/m")
assert (3.0 / a).GetValueAndUnit() == (1.5, "1/m")
assert b / a == b * 1 / a == b * (1.0 / a)


def testPow(unit_database_len_time):
s = Scalar(2, "s", "Time")
spow = s ** 3
Expand Down
10 changes: 10 additions & 0 deletions src/barril/units/unit_database.py
Original file line number Diff line number Diff line change
Expand Up @@ -1283,6 +1283,16 @@ def Divide(self, quantity1, quantity2, value1, value2):
quantity1, quantity2, value1, value2, lambda a, b: a - b, lambda a, b: a / b
)

def FloorDivide(self, quantity1, quantity2, value1, value2):
return self._DoOperationResultingInNewQuantity(
quantity1,
quantity2,
value1,
value2,
lambda a, b: a - b,
lambda a, b: a // b,
)

def Multiply(self, quantity1, quantity2, value1, value2):
"""
Multiplication with different quantities.
Expand Down

0 comments on commit cf9e39d

Please sign in to comment.