Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix division float over Scalar and float over Array #32

Merged
merged 1 commit into from
Oct 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 [
arthursoprana marked this conversation as resolved.
Show resolved Hide resolved
"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)
arthursoprana marked this conversation as resolved.
Show resolved Hide resolved


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