|
| 1 | +# Units |
| 2 | + |
| 3 | +[](https://codecov.io/gh/LLNL/units) |
| 4 | +[](https://dev.azure.com/phlptp/units/_build/latest?definitionId=1&branchName=main) |
| 5 | +[](https://circleci.com/gh/LLNL/units) |
| 6 | +[](https://github.com/GMLC-TDC/HELICS-src/blob/main/LICENSE) |
| 7 | +[](https://units.readthedocs.io/en/latest/?badge=latest) |
| 8 | +[](https://results.pre-commit.ci/latest/github/LLNL/units/main) |
| 9 | + |
| 10 | +[What's new](./CHANGELOG.md) |
| 11 | + |
| 12 | +[Documentation](https://units.readthedocs.io/en/latest/) |
| 13 | + |
| 14 | +The Units library provides a means of working with units of measurement at runtime, including conversion to and from strings. It provides a small number of types for working with units and measurements and operations necessary for user input and output with units. For additional description and discussion see [Readme](https://github.com/LLNL/units/blob/main/README.md) |
| 15 | + |
| 16 | +## Table of contents |
| 17 | + |
| 18 | +- [Units](#units) |
| 19 | + - [Table of contents](#table-of-contents) |
| 20 | + - [Purpose](#purpose) |
| 21 | + - [Basic use case](#basic-use-case) |
| 22 | + - [Try it out](#try-it-out) |
| 23 | + - [Unit methods](#unit-methods) |
| 24 | + - [Unit Operators](#unit-operators) |
| 25 | + - [Measurement Operations](#measurement-operations) |
| 26 | + - [Measurement operators](#measurement-operators) |
| 27 | + - [Contributions](#contributions) |
| 28 | + - [Project Using the Units Library](#project-using-the-units-library) |
| 29 | + - [Release](#release) |
| 30 | + |
| 31 | +## Purpose |
| 32 | + |
| 33 | +A units library was needed to be able to represent units from a wide range of disciplines and be able to separate them from the numerical values for use in calculations when needed. The main drivers are |
| 34 | + |
| 35 | +1. converting units, often represented by strings, to a standardized unit set when dealing with user input and output. |
| 36 | +2. Being able to use the unit as a singular type that could contain any unit, and not introduce a huge number of types to represent all possible units. |
| 37 | +3. Being able to associate a completely arbitrary unit given by users with a generic interface and support conversions between those user defined units and other units. |
| 38 | +4. The library has its origins in power systems so support for per-unit operations was also lacking in the alternatives. |
| 39 | +5. Capture uncertainty and uncertainty calculations directly with a measurement |
| 40 | + |
| 41 | +The python wrapper around the library is mainly intended to be able to handle various string representations and easily handle conversions, along with some support for commodities and packaging. |
| 42 | + |
| 43 | +### Basic use case |
| 44 | + |
| 45 | +The primary use case for the library is string operations and conversion. For example if you have a library that does some computations with physical units. In the library code itself the units are standardized and well defined. For example take a velocity, internally everything is in meters per second, but there is a configuration file that takes in the initial data and you would like to broadly support different units on the input |
| 46 | + |
| 47 | +```python |
| 48 | +from units_llnl import unit |
| 49 | + |
| 50 | +u1 = unit("m") |
| 51 | +u2 = unit("cm") |
| 52 | +v1 = u1.convert(10, u2) |
| 53 | +assert v1 == 10 * 100 |
| 54 | + |
| 55 | +v2 = u1.convert(unit_out=u2, value=20) |
| 56 | +assert v2 == 2000 |
| 57 | +``` |
| 58 | + |
| 59 | +```python |
| 60 | +from units_llnl import measurement |
| 61 | + |
| 62 | +m1 = measurement("10 m") |
| 63 | +m2 = measurement("2.5 s") |
| 64 | +m3 = m1 / m2 |
| 65 | +m4 = measurement("4.0 m/s") |
| 66 | +assert m3 == m4 |
| 67 | +``` |
| 68 | + |
| 69 | +## Try it out |
| 70 | + |
| 71 | +If you want to try out the string conversion components. There is server running that can do the string conversions |
| 72 | + |
| 73 | +[Unit String Conversions](https://units.readthedocs.io/en/latest/_static/convert.html) |
| 74 | + |
| 75 | +For more details see the [documentation](https://units.readthedocs.io/en/latest/web/index.html) |
| 76 | + |
| 77 | +### Unit methods |
| 78 | + |
| 79 | +These operations apply to units and precise_units |
| 80 | + |
| 81 | +- `<unit>(<unit_data>)` construct from a base unit_data |
| 82 | +- `<unit>(<unit_data>, double multiplier)` construct a unit from a base data and a multiplier |
| 83 | +- `<unit>(double multiplier, <unit>)` construct from a multiplier and another unit |
| 84 | +- also available are copy constructor and copy assignments |
| 85 | +- `<unit> inv()` generate a new unit containing the inverse unit `m.inv()= 1/m` |
| 86 | +- `<unit> pow(int power)` take a unit to power(NOTE: beware of limits on power representations of some units, things will always wrap so it is defined but may not produce what you expect). `power` can be negative. |
| 87 | +- `bool is_exactly_the_same(<unit>)` compare two units and check for exact equivalence in both the unit_data and the multiplier, NOTE: this uses double equality |
| 88 | +- `bool has_same_base(<unit>|<unit_data>)` check if the <unit_data> is the same |
| 89 | +- `equivalent_non_counting(<unit>|<unit_data>)` check if the units are equivalent ignoring the counting bases |
| 90 | +- `bool is_convertible(<unit>)` check if the units are convertible to each other, currently checks `equivalent_non_counting()`, but some additional conditions might be allowed in the future to better match convert. |
| 91 | +- `int unit_type_count()` count the number of unit bases used, (does not take into consideration powers, just if the dimension is used or not. |
| 92 | +- `bool is_per_unit()` true if the unit has the per_unit flag active |
| 93 | +- `bool is_equation()` true if the unit has the equation flag active |
| 94 | +- `bool has_i_flag()` true if the i_flag is marked active |
| 95 | +- `bool has_e_flag()` true if the e_flag is marked active |
| 96 | +- `double multiplier()` return the unit multiplier as a double |
| 97 | + |
| 98 | +- `commodity()` get the commodity of the unit |
| 99 | +- `commodity(int commodity)` assign a commodity to the precise_unit. |
| 100 | + |
| 101 | +#### Unit Operators |
| 102 | + |
| 103 | +There are also several operator overloads that apply to units and precise_units. |
| 104 | + |
| 105 | +- `<unit>=<unit>*<unit>` generate a new unit with the units multiplied ie `m*m` does what you might expect and produces a new unit with `m^2` |
| 106 | +- `<unit>=<unit>/<unit>` generate a new unit with the units divided ie `m/s` does what you might expect and produces a new unit with meters per second. NOTE: `m/m` will produce `1` it will not automatically produce a `pu` though we are looking at how to make a 'pu_m\*m=m' so units like strain might work smoothly. |
| 107 | + |
| 108 | +- `bool <unit>==<unit>` compare two units. this does a rounding compare so there is some tolerance to roughly 7 significant digits for \<unit> and 13 significant digits for <precise_unit>. |
| 109 | +- `bool <unit>!=<unit>` the opposite of `==` |
| 110 | + |
| 111 | +precise_units can usually operate with a `precise_unit` or `unit`, `unit` usually can't operate on `precise_unit`. |
| 112 | + |
| 113 | +### Measurement Operations |
| 114 | + |
| 115 | +- `<measurement>(val, <unit>)` construct a unit from a value and unit object. |
| 116 | +- `double value() const` get the measurement value as a double. |
| 117 | +- `<measurement> convert_to(<unit>) const` convert the value in the measurement to another unit base |
| 118 | +- `<measurement> convert_to_base() const` convert to a base unit, i.e. a unit whose multiplier is 1.0 |
| 119 | +- `<unit> units() const` get the units used as a basis for the measurement |
| 120 | +- `<unit> as_unit() const` take the measurement as is and convert it into a single unit. For Examples say a was 10 m. calling as_unit() on that measurement would produce a unit with a multiplier of 10 and a base of meters. |
| 121 | +- `double value_as(<unit>)` get the value of a measurement as if it were measured in \<unit\> |
| 122 | + |
| 123 | +#### Measurement operators |
| 124 | + |
| 125 | +There are several operator overloads which work on measurements or units to produce measurements. |
| 126 | + |
| 127 | +- `'*', '/', '+','-'` are all defined for mathematical operations on a measurement and produce another measurement. |
| 128 | +- `%` `*`, and `/` are defined for \<measurement>\<op>\<double> |
| 129 | +- `*`, and `/` are defined for \<double>\<op>\<measurement> |
| 130 | + |
| 131 | +Notes: for regular measurements, `+` and `-` are not defined for doubles due to ambiguity of what that operation means. For `fixed_measurement` types this is defined as the units are known at construction and cannot change. For `fixed_measurement` types if the operator would produce a new measurement with the same units it will be a fixed measurement, if not it reverts to a regular measurement. |
| 132 | + |
| 133 | +- `==`, `!=`, `>`, `<`, `>=`, `<=` are defined for all measurement comparisons |
| 134 | +- `<measurement>=<double>*<unit>` |
| 135 | +- `<measurement>=<unit>*<double>` |
| 136 | +- `<measurement>=<unit>/<double>` |
| 137 | +- `<measurement>=<double>/<unit>` basically calling a number multiplied or divided by a `<unit>` produces a measurement, specifically `unit` produces a measurement and `precise_unit` produces a precise_measurement. |
| 138 | + |
| 139 | +## Contributions |
| 140 | + |
| 141 | +Contributions are welcome. See [Contributing](./CONTRIBUTING.md) for more details and [Contributors](./CONTRIBUTORS.md) for a list of the current and past Contributors to this project. |
| 142 | + |
| 143 | +## Project Using the Units Library |
| 144 | + |
| 145 | +Anyone else using the units library? Please let us know. |
| 146 | + |
| 147 | +- [HELICS](www.helics.org) |
| 148 | +- [GridDyn](https://github.com/LLNL/GridDyn) |
| 149 | +- [scipp](https://scipp.github.io/) |
| 150 | + |
| 151 | +## Release |
| 152 | + |
| 153 | +This units library is distributed under the terms of the BSD-3 clause license. All new |
| 154 | +contributions must be made under this license. [LICENSE](./LICENSE) |
| 155 | + |
| 156 | +SPDX-License-Identifier: BSD-3-Clause |
| 157 | + |
| 158 | +LLNL-CODE-773786 |
0 commit comments