Ts Lib Units #

Version #

v0.3.16

Table of Contents #

Summary#

This library stores the TetraScience standard unit strings, so they can easily be imported and used in Task Scripts

Unit Usage#

The Unit enum is used to store the TetraScience standard unit strings. It can be used in Task Scripts instead of manually typing out the unit strings:

from ts_lib_units import Unit
from ts_ids_core.schema import ValueUnit

temperature = ValueUnit(value=20, unit=Unit.DEGREE_CELSIUS)
print(temperature.dict())

# Output:
# {'value': 20, 'unit': 'DegreeCelsius'}

UnitParser Usage#

The UnitParser class is used to parse raw unit strings to the TetraScience standard unit strings in task scripts.

The class should be initialized with a mapping (or a list of mappings) of raw unit strings to the TetraScience standard unit strings. The UnitParser.parse method can then be used to parse a raw unit string to the TetraScience standard unit string:

from ts_lib_units import Unit, UnitParser

MY_MAPPING = {
    "°C": Unit.DEGREE_CELSIUS,
    "ng/ml": Unit.NANOGRAM_PER_MILLILITER,
}

unit_parser = UnitParser(MY_MAPPING)

parsed_unit = unit_parser.parse("°C")
print("Parsed unit: ", parsed_unit)

# Output:
# Parsed unit:  DegreeCelsius

If the raw unit string is not in the mapping, the raw unit string will be returned, and stored within the UnitParser.unmapped_units set. This can then be used to log a warning for all units that could not be parsed:

import logging

from ts_lib_units import Unit, UnitParser

MY_MAPPING = {
    "°C": Unit.DEGREE_CELSIUS,
    "ng/ml": Unit.NANOGRAM_PER_MILLILITER,
}

unit_parser = UnitParser(MY_MAPPING)

parsed_unit = unit_parser.parse("m")
print("Parsed unit: ", parsed_unit)

if unit_parser.unmapped_units:
    logging.warning(
        "The following units could not be parsed to the TetraScience standard unit "
        f"strings: \n {sorted(list(unit_parser.unmapped_units))}"
    )

# Output:
# Parsed unit:  m
# WARNING:root:The following units could not be parsed to the TetraScience standard unit strings:
# ['m']

To avoid adding many similar warnings to the workflow logs, it is recommended to only log the unmapped units once per workflow run, for the entire set of unmapped units.

Standard Mappings#

A number of standard mappings are available in this library:

Mapping

Description

CONCENTRATION_MAPPING

Maps concentration units, like mg/ml, and M (molar)

MOLE_MAPPING

Maps mole units, like mol

MOLAR_MASS_MAPPING

Maps molar mass units, like g/mol

TEMPERATURE_MAPPING

Maps temperature units, like °C and °F

LENGTH_MAPPING

Maps length units, like m and mm

MASS_MAPPING

Maps mass units, like g and kg

TIME_MAPPING

Maps time units, like s and min

VOLUME_MAPPING

Maps volume units, like ml and L

These can be imported in Task Scripts and used with any custom mappings to create a UnitParser instance:

from ts_lib_units import UnitParser, TEMPERATURE_MAPPING

custom_mappings = {
    "mg/ml": Unit.MILLIGRAM_PER_MILLILITER,
}
unit_parser = UnitParser([TEMPERATURE_MAPPING, custom_mappings])

Unit Library#

All units are singular rather than plural, e.g. Meter as in 1 Meter rather than Meters as in 2 Meters. If the unit cannot be found in this library, request for it to be added. New units will be added following this approach:

  1. If the unit is in QUDT, or Allotrope QUDT-extended, the name in the URI will be used.

    • See the allotrope-qudt-merged.txt file for reference.

  2. Otherwise:

    1. Use Pascal case.

    2. Use Per for units divided by another unit.

    3. Simply concatenate units when it is one unit multiplied by another unit, e.g. VoltMeter.

    4. Do not capitalize after prefixes such as Milli or Micro.

Finding a QUDT URI for a New Unit#

When adding a new unit, use the semantic search tool to find the correct QUDT URI.

Step 1: Set up the vector database (first time only)

# Install search dependencies (optional group, not installed by default)
poetry install --with search

# Index the QUDT units (creates .qudt_vectordb/ directory)
poetry run index-qudt

To remove the search dependencies afterwards, recreate the venv without the group:

poetry env remove --all
poetry install

Step 2: Search for your unit

# Search by name, symbol, or description
poetry run search-qudt "milligrams per liter"
poetry run search-qudt "RLU"
poetry run search-qudt "concentration unit" --top 10

Example output:

1. URI: http://purl.allotrope.org/ontology/qudt-ext/unit#MilligramPerLiter
   Labels: Milligram per Liter
   Symbols: mg/L
   Similarity: 0.878

2. URI: http://qudt.org/vocab/unit/MilliGM-PER-L
   Labels: Milligram per Litre
   Symbols: mg/L
   Similarity: 0.827

Step 3: Choose the correct URI

  • Prefer Allotrope URIs (http://purl.allotrope.org/...) when available

  • Use QUDT URIs (http://qudt.org/...) if no Allotrope equivalent exists

  • If no match is found, the unit may not exist in QUDT - use qudt_uri=None

Step 4: Validate after adding

After adding a new unit, run the validation script:

poetry run validate-qudt-uris

Unit Conversion#

The convert_unit function can be used to convert a RawValueUnit or ValueUnit instance from one unit to another:

from ts_lib_units import convert_unit, Unit

previous = RawValueUnit(
  raw_value = "20 g/L",
  value = 20,
  unit = "GramPerLiter"
)

converted = convert_unit(previous, Unit.MILLIGRAM_PER_LITER)
print(converted)
# Output:
# ValueUnit(value=20000, unit='MilligramPerLiter')

Changelog#

v0.3.16 #

  • Add Nanoliter

  • Add MeterPerSecond

v0.3.15 #

  • Add EndotoxinUnit

v0.3.14 #

  • Add EndotoxinUnitPerMicroliter

  • Add EndotoxinUnitPerLiter

  • Add EndotoxinUnitPerNanogram

  • Add EndotoxinUnitPerMicrogram

  • Add EndotoxinUnitPerGram

  • Add ENDOTOXIN_MAPPING

v0.3.13 #

  • Add EndotoxinUnitPerMilliliter

v0.3.12 #

  • Add LICENSE

v0.3.11 #

  • Add SquareMicrometer

v0.3.10 #

  • Add ImportError with helpful message to search_qudt.py and index_qudt_units.py when search dependencies are not installed

v0.3.9 #

  • Move chromadb, sentence-transformers, and rdflib into an optional search dependency group

  • Run poetry install --with search to install these dependencies when using the QUDT search/index tools

v0.3.8 #

  • Add QUDT vector database search tooling for finding unit URIs via semantic similarity

  • Expose CLI commands via poetry run: search-qudt, index-qudt, download-qudt, validate-qudt-uris

v0.3.7 #

  • Add InternationalUnitPerLiter for enzyme activity

v0.3.6 #

  • Add mmol/L mapping to MillimolePerLiter in CONCENTRATION_MAPPING

v0.3.5 #

  • Add Femtoliter, CountPerLiter, CountPerMicroliter, CountPerMilliliter, CountPerNanoliter

v0.3.4 #

  • Add KilocaloriePerMole, MoleFraction

v0.3.3 #

  • Add CubicCentimeterPerMole, GramPerLiterSolvent, GramPerLiterSolution, JoulePerMole, KiloJoulePerMole, SquareRootMegaPascal

v0.3.2 #

  • Add PerSecond, PascalSecond, MillipascalSecond

  • Deprecate Permittivity which is a quantity rather than a unit

  • Fix QUDT URIs for GramPerMilliliter, LiterPerMinute, Microvolt

v0.3.1 #

  • Fix MilliAbsorbanceUnit, MilliAbsorbanceUnitTimesMinute and MilliAbsorbanceUnitTimesMilliliter unit definitions

v0.3.0 #

  • Modify UnitParser.parse method:

    • Allow to map to None type

    • Map empty string, “”, to None as a rule

  • Add units AbsorbanceUnit, MilliAbsorbanceUnit, MilliAbsorbanceUnitTimesMinute, MilliAbsorbanceUnitTimesMilliliter, CentimeterPerHour, CycleNumber, and LiterPerHour

v0.2.1 #

  • Add units MillivoltPerPH and MilliVolt

v0.2.0 #

  • Update the unit library to also store the following for each unit:

    • The QUDT / Allotrope QUDT Extended URI.

    • The representation of the unit according to the pint library, which is used for unit conversion.

  • Update the following unit strings to improve consistency between unit strings compared to the Allotrope / QUDT standards:

    • CentiPoise to Centipoise

    • FemtoGram to Femtogram

    • MilliSiemen to Millisiemens

    • MilliSiemensPerCentimeter to MillisiemensPerCentimeter

    • OsmolePerLiter to OsmolesPerLiter

  • Add the unit PerMinute

  • Add convert_unit function to convert a RawValueUnit or ValueUnit instance from one unit to another, using the pint library.

v0.1.5 #

  • Add unit MilliSiemen, LiterPerSquareMeter, MilliSiemensPerCentimeter, LiterPerSquareMeterPerMinute, LiterPerSquareMeterPerHour, LiterPerSquareMeterPerHourPerPoundPerSquareInch

v0.1.4 #

  • Add unit MillimolePerLiter

v0.1.3 #

  • Add units MilliDegreeAngle, NanometerPerMinute

  • Add mapping for "NANOMETERS" -> "Nanometer", "msec" -> "MilliSecond", "ul" -> "Microliter"

v0.1.2 #

  • Add PERCENT_MAPPING

v0.1.1 #

  • Fix bug where Unit.NANOGRAM_PER_LITER mapped to “NanogramPerMilliliter”

v0.1.0 #

  • Initial version