The package unitexpr
provides classes and meta-classes that
make it trivial to define custom unit systems and numpy
arrays
with unit support.
A search on pypi shows that there are a few packages available
for doing unit analysis. The most notable I found is scimath
,
which supports unit conversion and working with united numpy arrays.
The section below contains benchmarks comparing the performance of
unitexpr
units with those provided by the
package scimath
.
Note: To run the benchmarks one must install the packages:
pytest-benchmark
and pytest
.
To run the benchmarks clone the repository available at
unitexpr
, navigate to the package root directory
and use the command:
$ pytest benchmarks/unit_benchmark.py
An excerpt of a sample output (produced on a PC with 32GB RAM memory and an Intel Core i5-6260U CPU running at 1.80GHz) is displayed below:
-------------------------------- benchmark: 6 tests -----------------------------------
Name (time in ns) Mean StdDev Rounds Iterations
---------------------------------------------------------------------------------------
test_compare_scimath_units 384.6454 (1.0) 49.9329 (1.0) 4 20000
test_compare_unitexpr_units 455.8162 (1.19) 62.7644 (1.26) 4 20000
test_add_scimath_units 3,698.7334 (9.62) 199.3424 (3.99) 4 20000
test_add_unitexpr_units 5,527.3140 (14.37) 666.3501 (13.34) 4 20000
test_mult_scimath_units 4,363.7948 (11.34) 204.8872 (4.10) 4 20000
test_mult_unitexpr_units 5,780.7208 (15.03) 205.6521 (4.12) 4 20000
---------------------------------------------------------------------------------------
As the test runs above show scimath
unit comparisons and unit
operations are calculated slightly faster compared to unitexpr
units.
This result is expected due to the additional computational effort
involved with keeping track of unitexpr
terms as
well as type checking required
during comparison and arithmetic operations.
For the purpose of optimization scimath
computes and stores unit
expressions in terms of base units. The package
unitexpr
stores unit expressions in terms of
base units and derived units.
To support scientific calculation
the package also includes a united array.
The class qarray
extends numpy's ndarray
adding the additional
instance attribute unit
(with default value 1.0).
The section below contains benchmarks comparing the performance of
unitexpr
united numpy arrays with united arrays
provided by the package scimath
.
To run the benchmarks from the root directory of the
package unitexpr
use the command:
$ pytest benchmarks/qarray_benchmark.py
A sample output (not all columns are shown) produced on a PC with 32GB RAM memory and an Intel Core i5-6260U CPU running at 1.80GHz is displayed below:
---------------------------- benchmar: 4 tests -------------------------
Name (time in us) Mean StdDev Rounds Iterations
-------------------------------------------------------------------------
test_add_qarray 68.1265 (1.05) 21.3399 (4.15) 4 700
test_add_unit_array 81.0177 (1.25) 6.1296 (1.19) 4 700
test_mult_qarray 65.4302 (1.01) 5.1430 (1.0) 4 700
test_mult_unit_array 64.8208 (1.0) 7.3627 (1.43) 4 700
-------------------------------------------------------------------------
To produce the benchmarks the following arrays were constructed:
from numpy import ndarray, array_equal
from unitexpr.si_units import m, s, SiUnit
from unitexpr.qarray import qarray
from scimath.units.length import meter, centimeter
from scimath.units.time import second
from scimath.units.mass import kilogram
from scimath.units.unit_array import UnitArray as UnitArraySci
cm = SiUnit("cm", "centimeter", "length", 1.0e-2 * m)
nx = 200
ny = 200
A = ndarray(shape=(nx, ny))
A.fill(10.0)
M = qarray.from_input(A, unit=m ** 2)
C = qarray(shape=(nx, ny), unit=cm ** 2)
C.fill(1.0e4)
S = qarray.from_input(A, unit=s)
R = qarray(shape=(nx, ny), unit=m ** 2)
R.fill(11)
A1 = UnitArraySci(A)
M1 = UnitArraySci(A, units=meter * meter)
C1 = UnitArraySci(C, units=centimeter * centimeter)
S1 = UnitArraySci(A, units=second)
R1 = UnitArraySci(R, units=meter * meter)
The first set of benchmarks was produced by repeatedly calculating the
expressions: M + C
and M1 + C1
.
The second set of benchmarks was produced by calculating
M/(S**2)
and M1/(S1**2)
.
The results displayed above show that the performance of
unitexpr
and scimath
united arrays is similar.
As a rough estimate calculations involving units are of the order of microseconds to tens of microseconds (depending on the complexitiy of the unit expression).
The fraction of computational time spent on unit operations becomes negligable when performing calculations on large arrays with more than 50000 elements.
Please file feature requests and bugs at the issue tracker. Contributions are welcome.