Source code for pyenzyme.enzymeml.tools.unitcreator

# File: unitcreator.py
# Project: tools
# Author: Jan Range
# License: BSD-2 clause
# Copyright (c) 2022 Institute of Biochemistry and Technical Biochemistry Stuttgart

import libsbml

from deepdiff import DeepDiff

from pyenzyme.enzymeml.core.unitdef import UnitDef
from pyenzyme.enzymeml.tools.unitparser import UnitParser


[docs]class UnitCreator: def __init__(self): self.__functionDict = { "M": self.__Molar, "mole": self.__Mole, "l": self.__Volume, "liter": self.__Volume, "litre": self.__Volume, "g": self.__Amount, "gram": self.__Amount, "s": self.__Seconds, "sec": self.__Seconds, "second": self.__Seconds, "seconds": self.__Seconds, "min": self.__Minutes, "mins": self.__Minutes, "minutes": self.__Minutes, "h": self.__Hours, "hour": self.__Hours, "hours": self.__Hours, "C": self.__Celsius, "celsius": self.__Celsius, "Celsius": self.__Celsius, "K": self.__Kelvin, "kelvin": self.__Kelvin, "Kelvin": self.__Kelvin, "dimensionless": self.__Dimensionless, }
[docs] def getUnit(self, unit_string, enzmldoc) -> str: """ Args: String unit_string: Standard short form of unit """ if unit_string.count("/") > 1: splitted = unit_string.split("/") corrected = splitted[0] + "/" + "".join(splitted[1::]) raise ValueError( f"Unit '{unit_string}' contains multiple backlashes. Please stick to using a single backslash instead for units involving two or more base units per side. Use the following to enter your unit '{corrected}'" ) # Generate ID id = enzmldoc._generateID(prefix="u", dictionary=enzmldoc._unit_dict) # Call unit parser to identify units parser = UnitParser() units = sorted(parser.parse(unit_string)) # Initialize UnitDef nominator, denominator = [], [] for prefix, baseunit, exponent in units: pre_unit = "".join([prefix, baseunit]) if float(exponent) > 0: if abs(float(exponent)) > 1: nominator.append(pre_unit + f"^{exponent[1::]}") if abs(float(exponent)) == 1: nominator.append(pre_unit) else: if abs(float(exponent)) > 1: denominator.append(pre_unit + f"^{exponent[1::]}") if abs(float(exponent)) == 1: denominator.append(pre_unit) # Reformat unit string to a convenient format if not nominator: nominator = ["1"] if denominator: name = " / ".join([" ".join(nominator), " ".join(denominator)]) if not denominator: name = " ".join(nominator) # Convert Celsius to Kelvin - No SBML kind for C! if name.lower() == "c": name = "K" # Initialize UnitDef object unitdef = UnitDef(name=name, id=id) for prefix, baseunit, exponent in units: self.__functionDict[baseunit](unitdef, prefix, exponent) # Check if there is already a similar unit defined if self.__checkFootprints(enzmldoc, unitdef.getFootprint()) != "NEW": return self.__checkFootprints(enzmldoc, unitdef.getFootprint()) enzmldoc._unit_dict[unitdef.id] = unitdef return unitdef.id
def __checkFootprints(self, enzmldoc, footprint): for unit_id, unitdef in enzmldoc._unit_dict.items(): if DeepDiff(unitdef.getFootprint(), footprint) == {}: return unit_id return "NEW" def __Mole(self, unitdef, prefix, exponent): kind = libsbml.UnitKind_toString(libsbml.UNIT_KIND_MOLE) scale = self.__getPrefix(prefix) multiplier = 1 unitdef.addBaseUnit(kind, exponent, scale, multiplier) def __Molar(self, unitdef, prefix, exponent): self.__Mole(unitdef, prefix, exponent) kind = libsbml.UnitKind_toString(libsbml.UNIT_KIND_LITRE) scale = 1 multiplier = 1 unitdef.addBaseUnit(kind, -1, scale, multiplier) def __Volume(self, unitdef, prefix, exponent): kind = libsbml.UnitKind_toString(libsbml.UNIT_KIND_LITRE) scale = self.__getPrefix(prefix) multiplier = 1 unitdef.addBaseUnit(kind, exponent, scale, multiplier) def __Amount(self, unitdef, prefix, exponent): kind = libsbml.UnitKind_toString(libsbml.UNIT_KIND_GRAM) scale = self.__getPrefix(prefix) multiplier = 1 unitdef.addBaseUnit(kind, exponent, scale, multiplier) def __Seconds(self, unitdef, prefix, exponent): kind = libsbml.UnitKind_toString(libsbml.UNIT_KIND_SECOND) scale = 1 multiplier = 1 unitdef.addBaseUnit(kind, exponent, scale, multiplier) def __Minutes(self, unitdef, prefix=None, exponent=1): kind = libsbml.UnitKind_toString(libsbml.UNIT_KIND_SECOND) scale = 1 multiplier = 60 unitdef.addBaseUnit(kind, exponent, scale, multiplier) def __Hours(self, unitdef, prefix=None, exponent=1): kind = libsbml.UnitKind_toString(libsbml.UNIT_KIND_SECOND) scale = 1 multiplier = 60 * 60 unitdef.addBaseUnit(kind, exponent, scale, multiplier) def __Celsius(self, unitdef, prefix=None, exponent=1): kind = libsbml.UnitKind_toString(libsbml.UNIT_KIND_KELVIN) scale = 1 multiplier = 1 unitdef.addBaseUnit(kind, exponent, scale, multiplier) def __Kelvin(self, unitdef, prefix=None, exponent=1): kind = libsbml.UnitKind_toString(libsbml.UNIT_KIND_KELVIN) scale = 1 multiplier = 1 unitdef.addBaseUnit(kind, exponent, scale, multiplier) def __Dimensionless(self, unitdef, prefix=None, exponent=1): kind = libsbml.UnitKind_toString(libsbml.UNIT_KIND_DIMENSIONLESS) scale = 1 multiplier = 1 exponent = 1 unitdef.addBaseUnit(kind, exponent, scale, multiplier) def __getPrefix(self, prefix): if prefix == "f": return -15 elif prefix == "p": return -12 elif prefix == "n": return -9 elif prefix == "u": return -6 elif prefix == "m": return -3 elif prefix == "c": return -2 elif prefix == "d": return -1 elif prefix == "k": return 3 elif len(prefix) == 0: return 1 else: raise KeyError(f"Prefix {prefix} is unknown. Please define unit manually")