Functions

Expression Functions

The following functions are available in expr fields within slot derivations. See the Expression Language guide for full details on syntax and null propagation.

Function Description
str(x) Convert to string (distributes over lists)
int(x) Convert to integer (distributes over lists)
float(x) Convert to float (distributes over lists)
bool(x) Convert to boolean (distributes over lists)
abs(x) Absolute value (distributes over lists)
round(x) Round number (distributes over lists)
strlen(x) String length (distributes over lists)
max(items) Maximum of a list
min(items) Minimum of a list
len(items) Length of a list
case(pairs...) Conditional — first matching (condition, value) pair
uuid5(namespace, name) Deterministic UUID v5 generation

Unit Conversion

Basic unit conversion functions.

Currently only native pint units or UCUM units are supported.

For UCUM, the ucumvert library is used to convert UCUM units to pint units, see <https://github.com/dalito/ucumvert>_.

DimensionalityError

Bases: Exception

Raised when a unit conversion cannot be performed.

Note: equivalent to the pint error, but the pint dependency is optional

Source code in src/linkml_map/functions/unit_conversion.py
46
47
48
49
50
51
52
class DimensionalityError(Exception):
    """
    Raised when a unit conversion cannot be performed.

    Note: equivalent to the pint error, but the
    pint dependency is optional
    """

QuantitySyntaxError

Bases: Exception

Raised when a quantity cannot be parsed.

Source code in src/linkml_map/functions/unit_conversion.py
40
41
42
43
class QuantitySyntaxError(Exception):
    """
    Raised when a quantity cannot be parsed.
    """

UndefinedUnitError

Bases: Exception

Raised when a unit is not defined.

Note: equivalent to the pint error, but the pint dependency is optional

Source code in src/linkml_map/functions/unit_conversion.py
31
32
33
34
35
36
37
class UndefinedUnitError(Exception):
    """
    Raised when a unit is not defined.

    Note: equivalent to the pint error, but the
    pint dependency is optional
    """

UnitSystem

Bases: str, Enum

Enumeration of supported unit systems.

Source code in src/linkml_map/functions/unit_conversion.py
18
19
20
21
22
23
class UnitSystem(str, Enum):
    """Enumeration of supported unit systems."""

    UCUM = "ucum"
    IEC61360 = "iec61360"
    SI = "SI"

convert_units(magnitude, from_unit, to_unit, system=None)

Convert a quantity between units.

convert_units(1, "m", "cm") 100.0 convert_units(1, "m", "cm", system=UnitSystem.UCUM) 100.0 convert_units(1, "m", "cm", system=UnitSystem.SI) 100.0 convert_units(1.0, "hectare", "m^2", system=UnitSystem.SI) 10000.0 convert_units(1.0, "hectare", "m ** 2", system=UnitSystem.SI) 10000.0 convert_units(1.0, "hectare", "m ** 2", system=None) 10000.0 convert_units(1.0, "km2", "m2", system=UnitSystem.UCUM) 1000000.0 convert_units("100", "m", "cm") 10000.0 convert_units("3.14", "m", "cm") 314.0

:param magnitude: :param from_unit: :param to_unit: :return: converted magnitude

Source code in src/linkml_map/functions/unit_conversion.py
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
def convert_units(
    magnitude: float | int | str, from_unit: str, to_unit: str, system: UnitSystem | None = None
) -> float:
    """
    Convert a quantity between units.

    >>> convert_units(1, "m", "cm")
    100.0
    >>> convert_units(1, "m", "cm", system=UnitSystem.UCUM)
    100.0
    >>> convert_units(1, "m", "cm", system=UnitSystem.SI)
    100.0
    >>> convert_units(1.0, "hectare", "m^2", system=UnitSystem.SI)
    10000.0
    >>> convert_units(1.0, "hectare", "m ** 2", system=UnitSystem.SI)
    10000.0
    >>> convert_units(1.0, "hectare", "m ** 2", system=None)
    10000.0
    >>> convert_units(1.0, "km2", "m2", system=UnitSystem.UCUM)
    1000000.0
    >>> convert_units("100", "m", "cm")
    10000.0
    >>> convert_units("3.14", "m", "cm")
    314.0

    :param magnitude:
    :param from_unit:
    :param to_unit:
    :return: converted magnitude
    """
    magnitude = float(magnitude)
    ureg: pint.UnitRegistry = get_unit_registry(system)
    from_unit = normalize_unit(from_unit, system)
    to_unit = normalize_unit(to_unit, system)
    try:
        from_unit_q = ureg.parse_units(from_unit)
    except lark.exceptions.UnexpectedCharacters as err:
        msg = f"Cannot parse unit: {from_unit}"
        raise UndefinedUnitError(msg) from err
    except pint.errors.UndefinedUnitError as err:
        msg = f"Unknown source unit: {from_unit}"
        raise UndefinedUnitError(msg) from err
    quantity = magnitude * from_unit_q
    try:
        return quantity.to(to_unit).magnitude
    except pint.errors.UndefinedUnitError as err:
        msg = f"Unknown target unit: {from_unit}"
        raise UndefinedUnitError(msg) from err
    except pint.errors.DimensionalityError as err:
        msg = f"Cannot convert from {from_unit} to {to_unit}"
        raise DimensionalityError(msg) from err

get_unit_registry(system=None) cached

Get a unit registry.

ureg = get_unit_registry(UnitSystem.UCUM) ureg.from_ucum("m/s2.kg") str() '1.0 kilogram * meter / second ** 2' ureg.from_ucum("m[H2O]{35Cel}") # UCUM code with annotation .to("mbar") ureg("degC") # a standard pint unit ureg.from_ucum("g/m2") _.to(ureg.from_ucum("kg/m2")) ureg.from_ucum("nmol/mmol{Cre}") sireg = get_unit_registry(UnitSystem.SI) sireg("degC") sireg("ha")

:param system: currently only supported values are None or UnitSystem.UCUM :return:

Source code in src/linkml_map/functions/unit_conversion.py
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
@lru_cache
def get_unit_registry(
    system: UnitSystem | None = None,
) -> pint.UnitRegistry | PintUcumRegistry:
    """
    Get a unit registry.

    >>> ureg = get_unit_registry(UnitSystem.UCUM)
    >>> ureg.from_ucum("m/s2.kg")
    <Quantity(1.0, 'meter * kilogram / second ** 2')>
    >>> str(_)
    '1.0 kilogram * meter / second ** 2'
    >>> ureg.from_ucum("m[H2O]{35Cel}")  # UCUM code with annotation
    <Quantity(1, 'm_H2O')>
    >>> _.to("mbar")
    <Quantity(98.0665, 'millibar')>
    >>> ureg("degC")   # a standard pint unit
    <Quantity(1, 'degree_Celsius')>
    >>> ureg.from_ucum("g/m2")
    <Quantity(1.0, 'gram / meter ** 2')>
    >>> _.to(ureg.from_ucum("kg/m2"))
    <Quantity(0.001, 'kilogram / meter ** 2')>
    >>> ureg.from_ucum("nmol/mmol{Cre}")
    <Quantity(1.0, 'nanomole / millimole')>
    >>> sireg = get_unit_registry(UnitSystem.SI)
    >>> sireg("degC")
    <Quantity(1, 'degree_Celsius')>
    >>> sireg("ha")
    <Quantity(1, 'hectare')>

    :param system: currently only supported values are None or UnitSystem.UCUM
    :return:
    """
    import pint

    ureg = pint.UnitRegistry()
    if not system:
        return ureg
    if system in REGISTRIES:
        return REGISTRIES[system]
    if system.value in dir(ureg.sys):
        ureg.default_system = system.value
        return ureg
    msg = f"Unknown unit system: {system}"
    raise NotImplementedError(msg)

normalize_unit(unit, system=None)

Normalize the unit to UnitSystem.UCUM, if possible.

Source code in src/linkml_map/functions/unit_conversion.py
155
156
157
158
159
160
161
162
163
164
165
166
167
168
def normalize_unit(unit: str, system: UnitSystem | None = None) -> str:
    """Normalize the unit to UnitSystem.UCUM, if possible."""
    if system is None or system != UnitSystem.UCUM:
        return unit

    # this is UnitSystem.UCUM
    try:
        return str(get_unit_registry(system).from_ucum(unit))
    except pint.errors.UndefinedUnitError as err:
        msg = f"Unknown unit: {unit}"
        raise UndefinedUnitError(msg) from err
    except lark.exceptions.UnexpectedCharacters as err:
        msg = f"Cannot parse unit: {unit}"
        raise UndefinedUnitError(msg) from err