From 39eeddda7030ef92c32dc27ca858fa9406986836 Mon Sep 17 00:00:00 2001 From: Elmir Jagudin Date: Mon, 17 Jun 2024 08:05:58 +0200 Subject: [PATCH] add utility module for unit conversions Adds mxcubecore.utils.units module, so there is a common place for unit converson utility functions. Adds some initial function to convert between time, energy, length and current units. --- CONTRIBUTING.md | 4 ++ mxcubecore/utils/units.py | 71 +++++++++++++++++++++++++++++++++ test/pytest/test_utils_units.py | 45 +++++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 mxcubecore/utils/units.py create mode 100644 test/pytest/test_utils_units.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ad0445a04e..9852e73a0d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -121,6 +121,10 @@ code base * Pixels are to be used for beam location (center) * Datetime YYYY-MM-DD HH:MM:SS(.ff) ,possibly with hundreds of seconds (ff), and with 24 hour clock. +When writing code that converts between different units, +it is recommended to use utility functions from {py:mod}`mxcubecore.utils.units` module. +This will to aid in the readability of the code. + #### Value update signals/callbacks The "valueChanged" and "stateChanged" signals should be used when a HardwareObjects value or state has been changed. Defined in for instance the base class [HardwareObject](https://github.com/mxcube/HardwareRepository/blob/ea8369ab2c08dbe539fd92ffee18fd21bb3a81b8/BaseHardwareObjects.py#L666), [AbstractMotor](https://github.com/mxcube/HardwareRepository/blob/master/HardwareObjects/abstract/AbstractMotor.py) and diff --git a/mxcubecore/utils/units.py b/mxcubecore/utils/units.py new file mode 100644 index 0000000000..7c5bbfa38f --- /dev/null +++ b/mxcubecore/utils/units.py @@ -0,0 +1,71 @@ +""" +Utility functions for converting between different units. +""" + +# +# time units +# + + +def us_to_sec(us: float) -> float: + """ + convert microseconds (μs) to seconds + """ + return us / 1_000_000.0 + + +def sec_to_us(sec: float) -> float: + """ + convert seconds to microseconds (μs) + """ + return sec * 1_000_000.0 + + +def sec_to_hour(sec: float) -> float: + """ + convert seconds to hours + """ + return sec / (60 * 60) + + +# +# energy units +# + + +def ev_to_kev(ev: float) -> float: + """ + convert eV value to KeV value + """ + return ev / 1000.0 + + +# +# length units +# + + +def meter_to_mm(meters: float) -> float: + """ + convert meters to millimeters (mm) + """ + return meters * 1000.0 + + +def mm_to_meter(millimeters: float) -> float: + """ + convert millimeters (mm) to meters + """ + return millimeters / 1000.0 + + +# +# current units +# + + +def A_to_mA(amp: float) -> float: + """ + convert Ampere (A) to milli Ampere (mA) + """ + return amp * 1000 diff --git a/test/pytest/test_utils_units.py b/test/pytest/test_utils_units.py new file mode 100644 index 0000000000..998f4e39cb --- /dev/null +++ b/test/pytest/test_utils_units.py @@ -0,0 +1,45 @@ +from math import isclose +from mxcubecore.utils.units import ( + us_to_sec, + sec_to_us, + sec_to_hour, + ev_to_kev, + meter_to_mm, + mm_to_meter, + A_to_mA, +) + + +def test_us_to_sec(): + assert isclose(us_to_sec(500_000), 0.5) + assert isclose(us_to_sec(123.4), 0.0001234) + + +def test_sec_to_us(): + assert isclose(sec_to_us(2), 2_000_000.0) + assert isclose(sec_to_us(0.42), 420_000.0) + + +def test_sec_to_hour(): + assert isclose(sec_to_hour(3800), 1.056, abs_tol=0.001) + assert isclose(sec_to_hour(1800.0), 0.5) + + +def test_ev_to_kev(): + assert isclose(ev_to_kev(12000), 12.0) + assert isclose(ev_to_kev(10.5), 0.0105) + + +def test_meter_to_mm(): + assert isclose(meter_to_mm(10), 10_000.0) + assert isclose(meter_to_mm(0.5214), 521.4) + + +def test_mm_to_meter(): + assert isclose(mm_to_meter(1200), 1.2) + assert isclose(mm_to_meter(10.5), 0.0105) + + +def test_A_to_mA(): + assert isclose(A_to_mA(2), 2000.0) + assert isclose(A_to_mA(0.3921), 392.1)