Skip to content

Commit 48e1486

Browse files
add helper method .dimensionless (#43)
2 parents 134f5ae + 77ec56b commit 48e1486

5 files changed

Lines changed: 40 additions & 4 deletions

File tree

test/test_value.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def test_construction() -> None:
2929
assert isinstance(3j * x, Value)
3030

3131

32-
def test_dimensionless() -> None:
32+
def test_dimensionless_act_like_float() -> None:
3333
"""Test that dimensionless values act like floats"""
3434
x = Value(1.5, '')
3535
y = Value(1.5, 'us/ns')
@@ -254,3 +254,12 @@ def test_sign() -> None:
254254
for x in np.linspace(-10, 10, 20):
255255
v = Value(x, 'ns')
256256
assert v.sign() == np.sign(x)
257+
258+
259+
def test_dimensionless() -> None:
260+
A, B = Value(1, 'GHz^2'), Value(1200, 'MHz/GHz')
261+
262+
with pytest.raises(ValueError):
263+
_ = A.dimensionless()
264+
265+
assert B.dimensionless() == 1.2

test/test_value_array.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,14 @@ def test_power() -> None:
8282
assert np.array_equal((s * [1, 2, 3]) ** 2, s * s * [1, 4, 9])
8383

8484

85+
def test_dimensionless_act_like_arrays() -> None:
86+
x = ValueArray(1.5 * np.arange(5), '')
87+
y = ValueArray(1.5 * np.arange(5), 'us/ns')
88+
89+
np.testing.assert_allclose(np.sqrt(x), np.sqrt(1.5 * np.arange(5)))
90+
np.testing.assert_allclose(np.sin(y), np.sin(1.5 * np.arange(5) * 1000))
91+
92+
8593
def test_repr() -> None:
8694
from tunits.units import km, kg, s
8795

@@ -206,18 +214,27 @@ def test_divison_with_dimensionless_preserves_ratios() -> None:
206214

207215

208216
def test_units() -> None:
209-
A, B = Value(np.random.random(10), 'GHz^2'), Value(np.random.random(10), 'MHz/GHz')
217+
A, B = ValueArray(np.random.random(10), 'GHz^2'), ValueArray(np.random.random(10), 'MHz/GHz')
210218
assert A.units == 'GHz^2'
211219
assert B.units == 'MHz/GHz'
212220

213221

214222
def test_base_unit() -> None:
215-
A, B = Value(np.random.random(10), 'GHz^2'), Value(np.random.random(10), 'MHz/GHz')
223+
A, B = ValueArray(np.random.random(10), 'GHz^2'), ValueArray(np.random.random(10), 'MHz/GHz')
216224
assert A.base_unit == Value(1, 'Hz^2')
217225
assert B.base_unit == Value(1, '')
218226

219227

220228
def test_sign() -> None:
221229
for x in np.random.random((10, 3, 4)):
222-
v = Value(x, 'ns')
230+
v = ValueArray(x, 'ns')
223231
np.testing.assert_equal(v.sign(), np.sign(x))
232+
233+
234+
def test_dimensionless() -> None:
235+
A, B = ValueArray([1, 2, 3], 'GHz^2'), ValueArray(np.arange(5), 'MHz/GHz')
236+
237+
with pytest.raises(ValueError):
238+
_ = A.dimensionless()
239+
240+
np.testing.assert_equal(B.dimensionless(), np.arange(5) / 1000)

tunits/core/__init__.pyi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ class Value(Generic[NumericalT], WithUnit, np.generic, SupportsIndex):
317317
def __index__(self) -> int: ...
318318
def __pow__(self, other: Any, modulus: Any = None) -> Value: ...
319319
def sign(self) -> int: ...
320+
def dimensionless(self) -> float: ...
320321

321322
class ValueArray(Generic[ValueType2], WithUnit):
322323
value: NDArray[Any]
@@ -378,6 +379,7 @@ class ValueArray(Generic[ValueType2], WithUnit):
378379
) -> ValueArray: ...
379380
def __pow__(self, other: Any, modulus: Any = None) -> ValueArray: ...
380381
def sign(self) -> NDArray[np.integer]: ...
382+
def dimensionless(self) -> NDArray[Any]: ...
381383

382384
def init_base_unit_functions(
383385
try_interpret_as_with_unit: Callable[[Any, bool], WithUnit | None],

tunits/core/cython/with_unit.pyx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,11 @@ cdef class WithUnit:
669669
def sign(self) -> int | np.ndarray:
670670
return np.sign(self.value_in_base_units())
671671

672+
def dimensionless(self) -> float | np.ndarray:
673+
if not self._is_dimensionless():
674+
raise ValueError(f'{self} is not dimensionless')
675+
return self.value_in_base_units()
676+
672677
_try_interpret_as_with_unit = None
673678
_is_value_consistent_with_default_unit_database = None
674679
def init_base_unit_functions(

tunits/core/cython/with_unit_value_array.pyx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ class ValueArray(WithUnit):
144144
]:
145145
return getattr(ufunc, method)(*(np.asarray(x) for x in inputs), **kwargs)
146146

147+
if self._is_dimensionless():
148+
return getattr(ufunc, method)(*(np.asarray(x) for x in inputs), **kwargs)
149+
147150
raise NotImplemented
148151

149152
@property

0 commit comments

Comments
 (0)