Fundamental Units

units.py module

The units module provides a robust framework for handling physical quantities with automatic SI prefix resolution and CODATA-precise conversions.

The units converters are defined as classes: PhysicalQuantity, Energy, Pressure, Length, Area, Volume, Mass, MolarMass, Density.

Quick Start

Initialization

Users must first import the appropriate class from tools4pyPhysChem, e.g.:

from pyphyschemtools import Pressure

There are two ways to initialize quantities: you can create objects using standard initialization or the human-readable `parse` method.
  • Manual Initialization: Pass a value and a unit string.

  • String Parsing: Use .parse() for scientific strings like "13.6 eV" or "1.672e2 nm".

# Standard way: (value, unit)
p1 = Pressure(1, 'atm')

# Scientific string parsing:
p2 = Pressure.parse("760 torr")

# They are equivalent:
print(p1.to('Pa') == p2.to('Pa'))  # True

Smart Arithmetic

Basic operations

Addition and subtraction operations are performed in absolute SI space, but the result is automatically returned in the unit of the first operand to maintain consistency in your calculations

e1 = Energy(3, 'eV')
e2 = Energy(1.602177e-19, 'J')

# Result will be in 'eV' because e1 is the first variable
ep = e1 + e2  
print(ep)  # 4 eV
em = e1 + e2  
print(em)  # 2 eV

Arithmetic Rules

The units module enforces strict physical laws to ensure your calculations remain dimensionally sound:

  • Additive Operations (+, -): These are allowed only between compatible quantities (e.g., Mass + Mass). The result is always expressed in the unit of the first operand.

  • Scalar Scaling (*, /): You can multiply or divide any physical quantity by a scalar (integer, float, or NumPy array). This is useful for scaling measurements or applying coefficients.

  • Dimensional Protection: Multiplying or dividing two quantities (e.g., Pressure * Pressure) is forbidden. This prevents the accidental creation of complex derived units (like Pa2) that the specific classes are not designed to handle

In summary, arithmetic is allowed between compatible quantities or with scalars, while operations that would result in complex derived units are restricted.

Operation

Syntax

Allowed?

Resulting Type

Note

Addition

Mass + Mass

βœ…

Mass

Performed in SI, returned in the unit of the first operand.

Scalar Addition

Mass + 5.0

βœ…

Mass

The scalar is assumed to share the object’s unit.

Scaling

Mass * 2.0

βœ…

Mass

Doubling or halving the magnitude.

Division

Mass / 2.0

βœ…

Mass

Reducing the magnitude.

Dimensional Error

Mass * Mass

❌

TypeError

Forbidden to prevent uncontrolled unit exponentiation (\(g^2\)).

Inversion Error

1.0 / Mass

❌

TypeError

Forbidden to prevent unit inversion (\(g^{-1}\)).

Incompatibility

Mass + Energy

❌

TypeError

Strictly forbidden (cannot add apples to oranges).

Discovering Supported Units of each class

Each class knows its own supported base units. You can inspect them alongside global SI prefixes, with the command:

Volume.show_available_units()

CODATA Traceability & Metadata

Transparency is key in Physical Chemistry and in numerical calculations. You can inspect the exact physical constants (Planck, Boltzmann, etc.) used for internal calculations, sourced from the latest CODATA values via scipy.constants. It can be done either from a class associated to a physical quantity (Energy, etc…) of from the base PhysicalQuantity class.

from pyphyschemtools import Energy
Energy.show_constants_metadata()

or

from pyphyschemtools import PhysicalQuantity
PhysicalQuantity.show_constants_metadata()

Universal Prefix Support

The recursive prefix manager allows for extreme physical scales. It treats prefixes like da (deca) or y (yocto) as dynamic multipliers applicable to (almost) any base unit. Supported SI prefixes range from yocto, \(10^{-30}\), to quetta, \(10^{30}\).

print(Energy.parse("4000 ym-1").to('GeV'))
print(Energy.parse("4000 ym-1").to('ZJ/mol'))

The list of prefixes can also be obtained either from a class associated to a physical quantity (Energy, etc…) of from the base PhysicalQuantity class:

from pyphyschemtools import Energy
Energy.show_available_prefixes()

or

from pyphyschemtools import PhysicalQuantity
PhysicalQuantity.show_available_prefixes()

Accessing Numerical Data

The primary way to extract numerical values from a unit object, for example when you need to perform external calculations or pass the data to a plotting function (like Matplotlib) while keeping the original unit’s scale is to address it with :

from pyphyschemtools import Pressure
p = Pressure.parse("10.45 MPa").to('bar')
print(p) # 104.5000 bar
print(type(p)) # <class 'pyphyschemtools.units.Pressure'>
print(p.value) # 104.5
print(type(p.value)) # <class 'float'>
print(2*p) # 
print(2*p.value) # 

Batch Processing (Vectorization)

All classes are fully compatible with NumPy. You can pass a list or array of values to perform batch conversions. Let’s consider the energy levels of the Hydrogen atom:

K = 13.59844
Etab_eV = [-K, -K/4, -K/9, -K/16, -K/25]

# Convert the entire list from eV to hartree
Etab_hartree = Energy(Etab_eV, 'eV').to('hartree')

print(Etab_hartree) # Formatted output: Energy Array (hartree, shape=(5,))
print(Etab_hartree.value) # Formatted output: [-0.49973345 -0.12493336 -0.05552594 -0.03123334 -0.01998934]

Energy

Mathematical relationships

The Energy class is a high-level physical chemistry utility designed to handle the complex conversions between energy, wavelength, temperature, and molar quantities. It features a recursive prefix manager and native support for different energy contexts:

  • Photon Energy: Relates energy to wavelength (\(\lambda\)) or frequency (\(\nu\)):

\[E = h\nu = \frac{hc}{\lambda}\]
  • Wavenumbers: Handles reciprocal length units (\(\text{cm}^{-1}\)):

\[E = hc\bar{\nu}\]
  • Thermal Energy: Relates temperature (\(T\)) to energy via the Boltzmann constant (\(k_B\)):

\[E = k_B T\]
  • Molar Quantities: Bridges single-particle energy (\(E_{particle}\)) and macroscopic thermodynamic properties using the Avogadro constant (\(N_A\)):

\[E_\mathrm{molar} = E_\mathrm{particle} \cdot N_A\]

To use the energy unit conversion engine, import the Energy class as follows:

from pyphyschemtools import Energy

Spectroscopic & Molar Conversions

The class automatically detects whether a unit is an energy, a length (wavelength), or a reciprocal length (wavenumber). It also handles the conversion from single-particle energy to molar energy.

print(Energy.parse("4000 cm-1").to('eV'))      # Wavenumber to Energy
print(Energy.parse("1 MeV").to('kJ/mol'))      # Nuclear Energy to Molar Energy
print(Energy.parse("656 nm").to('eV'))         # Wavelength to Energy
print(Energy.parse("1 kcal/mol").to('kJ/mol')) # Thermochemical conversion

Supported units

Symbol

Name of the Unit

J

Joule (SI Base Unit)

eV

Electronvolt

hartree

Hartree

cal

Calorie (thermochemical)

erg

Erg

BTU

British Thermal Unit

K

Kelvin

m

Meter

Γ…, A

Γ…ngstrΓΆm

cm-1

Reciprocal Centimeter

unit-1

Any reciprocal unit length

unit/mol

Molar units