hec.unit

Module for unit definitions and conversions.

Uses the Pint unit library for operations. For any unit some or all of the following exist:

  • Pint unit: The Pint Unit object or a valid name or definition used to create a Pint Unit object
  • Unit name: The local name used to refer to the Pint unit
  • Unit aliases: (Optional) Aliases for the unit name All Pint Units may be defined in a Pint unit registry with specified names. However those names (but not the definitions) must adhere to Python identifier rules which elimiates many common unit names. Although non-identifier aliases can (sometimes) be associated with the unit definitions, there is no mechanism to output the units in those aliases. If a Pint Unit does not have a name, its definition is output in its place. For this reason,unit names and aliaes are maintained in dictionaries separate from the Pint library.

Example 1: Unit name is not a valid Python identifier but is the same as the Pint Unit definition

  • Unit name = g/l
  • Pint unit definition = g/l
  • Unit aliases =
    • gm/l
    • grams per liter
    • grams/liter
>>> from hec import unit
>>> g_per_l_unit = unit.get_pint_unit('g/l')
>>> print(repr(g_per_l_unit))
<Unit('gram / liter')>
>>> print(g_per_l_unit)
gram / liter
>>> print(f"{g_per_l_unit:D}")
gram / liter
>>> print(f"{g_per_l_unit:~D}")
g / l
>>> print(f"{g_per_l_unit:C}")
gram/liter
>>> print(f"{g_per_l_unit:~C}")
g/l
>>> print(f"{g_per_l_unit:P}")
gram/liter
>>> print(f"{g_per_l_unit:~P}")
g/l
>>> print(unit.get_unit_name(g_per_l_unit))
g/l
>>>

Example 2: Unit name is a valid Python identifier but is not the same as the Pint Unit definition

  • Pint unit definition = ft**3/s
  • Unit name = cfs
  • Unit aliases =
    • CFS
    • FT3/S
    • FT3/SEC
    • cu-ft/sec
    • cuft/sec
    • ft3/s
    • ft3/sec
    • ft^3/s
>>> from hec import unit
>>> cfs_unit = unit.get_pint_unit("CFS")
>>> print(repr(cfs_unit))
<Unit('foot ** 3 / second')>
>>> print(cfs_unit)
foot ** 3 / second
>>> print(f"{cfs_unit:D}")
foot ** 3 / second
>>> print(f"{cfs_unit:~D}")
ft ** 3 / s
>>> print(f"{cfs_unit:C}")
foot**3/second
>>> print(f"{cfs_unit:~C}")
ft**3/s
>>> print(f"{cfs_unit:P}")
foot³/second
>>> print(f"{cfs_unit:~P}")
ft³/s
>>> print(unit.get_unit_name(cfs_unit))
cfs
>>>
def convert_units( to_convert: Any, from_unit: Union[pint.registry.Unit, str], to_unit: Union[pint.registry.Unit, str], in_place: bool = False) -> Any:

Converts an object from one unit to another. If the object is non-convertable it is returned unchanged.

Arguments:
  • to_convert (Any): The object to convert. May be:
    • integer
    • float
    • string
    • Pint Quantity
    • list
    • tuple
    • cwms.cwms_types.Data
  • from_unit (Union[pint.Unit, str]): The unit to convert from. May be:
    • a unit name
    • a unit alias
    • a valid Pint unit string
    • a Pint unit
  • to_unit (Union[pint.Unit, str]): The unit to conver to. May be:
    • a unit name
    • a unit alias
    • a valid Pint unit string
    • a Pint unit
  • in_place (bool): for list and cwms.cwms_types.Data types, specifies whether to convert the object in-place. Ignored for all other data types. If True, the converted object is returned. If False, a converted copy is returned. Defaults to False
Raises:
  • UnitException: If:
    • A string is passed for one of the units that is not:
      • a unit name
      • a unit alias
      • a valid Pint unit string
    • The object to convert is Pint quantity or cwms.cwms_types.Data object whose unit is not the same as the from_unit.
Returns:

Any: if to_convert is:

  • integer or float: a float is returned
  • Pint Quantity:
    • if from_unit is the same as the unit of to_convert, a converted Pint Quantity is returned
    • if from_unit is not the same as the unit of to_convert, a UnitException is raised
  • string: a string is returned
    • if the string is numeric the returned string will be a string of the converted value
    • if the string is not numeric, it is returned unchanged
  • list:, a list returned with each item either converted or not as specified in the rules above. If in_place == True, the return value can be ignored if desired.
  • tuple:, a tuple returned with each item either converted or not as specified in the rules above. If in_place == True, the return value can be ignored if desired.
  • cwms.type.Data:, a cwms.type.Data object is returned. If in_place == True, the return value can be ignored if desired.

Otherwise to_convert is returned unchanged

def get_compatible_base_parameters( unit: Union[str, pint.registry.Unit], parameter_context: str = 'CWMS') -> list[str]:

Returns a list of base parameter names that are compatible with the specified unit

Arguments:
  • unit (Union[str, pint.Unit]): The unit object or unit name to retrieve the base parameter names for
  • parameter_context (str): The parameter context, defaults to "CWMS" (currently only valid context)
Raises:
  • UnitException: If an invalid context is specified
Returns:

list[str]: The compatible base parameter names

def get_compatible_units(unit: Union[str, pint.registry.Unit]) -> list[str]:

Returns a list of units names that are convertable to/from the specified unit

Arguments:
  • unit (Union[str, pint.Unit]): The unit to get compatible units for
Returns:

list[str]: The list of compatible unit names

def get_pint_unit(unit: str) -> pint.registry.Unit:

Gets the Pint unit object for a specified unit string

Arguments:
  • unit (str): The specified unit. May be a unit name, unit alias, or a Pint unit string
Raises:
  • UnitException: If the specified unit is not a valid unit name, unit alias, or Pint unit string
Returns:

pint.Unit: The Pint unit object

def get_unit_aliases(unit: Union[str, pint.registry.Unit]) -> list[str]:

Returns a list of aliases for the specified unit

Arguments:
  • unit (Union[str, pint.Unit]): A unit name, Pint Unit definition, or Pint Unit object
Raises:
  • KeyError: if the specified unit is not an existing unit name or a Pint Unit (definition or object) referenced by a unit_name
Returns:

list[str]: A list of aliases for the specified unit

def get_unit_context() -> pint.facets.context.objects.Context:

Returns the Pint unit registry context. See Pint documentation for more details.

Returns:

pint.facets.context.objects.Context: The unit registry context

def get_unit_name(name_alias_or_unit: Union[str, pint.registry.Unit]) -> str:

Returns the unit name of unit name, unit alias, or Pint unit (string or object)

Arguments:
  • name_alias_or_unit (Union[str, pint.Unit]): A unit name, unit alias or a Pint unit
Raises:
  • KeyError: If no unit name exists for the unit alias or Pint unit
Returns:

str: The unit_name

def get_unit_names_for_unit_system(unit_system: Optional[str]) -> list[str]:

Returns a list of unit names for the specified unit system

Arguments:
  • unit_system (Optional[str]): "EN", "SI", or None
Raises:
  • KeyError: if the specified unit system is not "EN", "SI", or None
Returns:

list[str]: A list of English unit names, Système International unit names, or unit names used by both (if unit_system is None)

def get_unit_registry() -> pint.registry.UnitRegistry:

Returns the Pint unit registry. Pint doesn't share unit information between registries so this registry must be used for any modification to the Pint behavior. See Pint documentation for more details.

Returns:

pint.registry.UnitRegistry: the Pint unit registry currently in use

def get_unit_system(unit: str) -> Optional[str]:

Returns the unit system of a unit name or unit alias

Arguments:
  • unit (str): A unit name or unit alias
Raises:
  • KeyError: if the specified unit is not an existing unit name or a Pint Unit (definition or object) referenced by a unit_name
Returns:

Optional[str]: "EN" if English, "SI" if Système International, or None if both

class UnitException(builtins.Exception):

Exception specific to Unit operations

@total_ordering
class UnitQuantity:

Class for scalar values with units.

Thinly wraps pint.UnitRegistry.Quantity, but allows non-identifier unit names to be associated with quantities. Can be used with mathematical, comparison, and conversion operators in conjuction with pint.UnitRegistry.Quantity objects and scalars (ints and floats).

UnitQuantity(*args: Any)

Creates a UnitQuantity object

Arguments:
  • One argument:
    • str: Either:
    • UnitQuantity: Another UnitQuantity object
    • pint.Quantity: A Pint Quantity object
  • Two arguments:
    • args[0] (Union[int, float, Fraction]): The magnitude of the quantity
    • args[1] (Union[str, pint.Unit): The uni of the quantity
Raises:
  • UnitException: if in valid arguments are specified
dimensionality: pint.util.UnitsContainer

The dimensionality of the object

Operations:

Read/Only

def get_compatible_base_parameters(self, parameter_context: str = 'CWMS') -> list[str]:

Returns a list of base parameter names that are compatible with this object.

Arguments:
  • parameter_context (str, optional): Currently only "CWMS" is supported. Defaults to "CWMS".
Returns:

list[str]: _description_

def get_compatible_units(self) -> list[str]:

Returns a list of compatible unit unit names for the specified unit of this object. Compatible units are those that have the same dimensionality.

Returns:

list[str]: The list of compatible unit names for this object's specified unit

def get_unit_aliases(self) -> list[str]:

Returns a list of unit aliases for the specified unit of this object

Returns:

list[str]: The list of unit aliases for this object's specified unit

def get_unit_systems(self) -> list[str]:

Returns a list of unit systems that include the name of this unit.

Returns:

list[str]: Will be [], ['EN'], ['SI'], or ['EN', 'SI']

isnan: bool

Whether the magnitude of the objed is NaN

Operations:

Read/Only

def ito(self, unit: Union[str, pint.registry.Unit]) -> UnitQuantity:

Converts this object to a different unit in place.

Identical to calling .to(..., in_place=True)

Arguments:
  • unit (Union[str, pint.Unit]): The unit ot convert to
Returns:

UnitQuantity: The converted object

magnitude: float

The magnitude of the object (unitless value)

Operations:

Read/Only

output_format: Optional[str]

The output format used for this object if a format specifier is not used. Any format specifier used will override this property.

If None, the unit name or alias specified when the object was creaed will be output (e.g., 10 dsf). See Pint format specification for other formats.

Operations:

Read/Write

def round(self, places: int = 0) -> UnitQuantity:

Returns a copy of this object with the magnitude rounded to the specified number of decimal places

Arguments:
  • places (int): The number of decimal places to round to. Default is 0.
Returns:

UnitQuantity: The rounded object

@classmethod
def set_default_output_format(cls, format: Optional[str]) -> None:

Sets the default output format for new UnitQuantity objects

Arguments:
  • format (Optional[str]):
    • None: (default value) outputs the units as specified when the UnitQuantity object was created
    • Other: Must be a valid Pint format specification
specified_unit: str

The unit specified when the object was created. May be a unit name, alias, or a pint unit definition

Operations:

Read/Only

def to( self, unit: Union[str, pint.registry.Unit], in_place: bool = False) -> UnitQuantity:

Converts this object to a different unit

Arguments:
  • unit (Union[str, pint.Unit]): The unit to convert to
  • in_place (bool, optional): If True, this object is modified and returned. Otherwise a new object is returned. Defaults to False.
Returns:

UnitQuantity: The converted object

unit: pint.registry.Unit

The Pint unit of the object

Operations:

Read/Only