SITypes: Unit Aware Calculations

Ideal Gas Law Example

Calculate the pressure exerted by 0.078 moles of hydrogen gas in a 42.0 mL container at 25.0 °C.

This problem requires the ideal gas equation: pV = nRT

Conventional Approach

The traditional method involves multiple steps:

  • n = 0.078 mol

  • T = 273.15 K + 25.0 K = 298.15 K

  • V = 42.0 mL

  • R = 8.314510 J/(K·mol)

Numerical calculation: p = nRT/V = 0.078 × 8.314510 × 298.15 ÷ 42.0 = 4.604...

However, an additional dimensional analysis needs to be performed:

mol × J/(K·mol) × K ÷ mL = J/mL

And then this result requires additional conversion to obtain pressure in atmospheres.

SITypes Approach

SITypes enables direct calculation with automatic unit management

First, import SITypes and demonstrate the calculation:

[ ]:
# Import SITypes
from rmnpy.wrappers.sitypes import Scalar

# Complete calculation with automatic unit conversion
pressure = Scalar("0.078 mol * R * (273.15 + 25.0) K / 42.0 mL")

# Convert to atmospheres as requested
pressure_atm = pressure.to("atm")
print(f"Pressure in atmospheres = {pressure_atm}")
Pressure in atmospheres = 45.4357 atm

The same calculation using discrete variables demonstrates SITypes’ flexibility with Python arithmetic operations:

[ ]:
# Create separate Scalar objects for each variable
n = Scalar("0.078 mol")              # amount of substance
R = Scalar("R")                      # gas constant (built-in physical constant)
T = Scalar("(273.15 + 25.0) K")      # temperature
V = Scalar("42.0 mL")                # volume

print(f"Variables:")
print(f"  n (amount) = {n}")
print(f"  R (gas constant) = {R}")
print(f"  T (temperature) = {T}")
print(f"  V (volume) = {V}")

# Calculate pressure using Python arithmetic: p = nRT/V
p = n * R * T / V
print(f"\nCalculation: p = nRT/V")
print(f"p = {p}")
print(f"p = {p.to('atm')} (in atmospheres)")

print(f"\nComparison:")
print(f"   String expression: {pressure_atm}")
print(f"   Python variables:  {p.to('atm')}")
Variables:
  n (amount) = 0.078 mol
  R (gas constant) = 1 R
  T (temperature) = 298.15 K
  V (volume) = 42 mL

Calculation: p = nRT/V
p = 4.60378e+06 mJ/L
p = 45.4357 atm (in atmospheres)

Comparison:
   String expression: 45.4357 atm
   Python variables:  45.4357 atm

SITypes includes fundamental physical constants in its database.

No manual entry is required for values like R = 8.314510 J/(K·mol). These constants can be used directly in expressions by their standard symbols.

[3]:
# Built-in Physical Constants Database
working_constants = [
    ("R", "Gas constant"),
    ("c_0", "Speed of light"),
    ("h_P", "Planck constant"),
    ("k_B", "Boltzmann constant"),
    ("N_A", "Avogadro constant"),
    ("q_e", "Elementary charge"),
    ("m_e", "Electron mass"),
    ("m_p", "Proton mass"),
    ("G", "Newton gravitational constant"),
    ("π", "Pi"),
    ("e", "Euler constant")
]

print("Selected Physical Constants:")
for symbol, description in working_constants:
    try:
        constant = Scalar(symbol)
        print(f"  {symbol:8} = {constant} ({description})")
    except:
        pass
Selected Physical Constants:
  R        = 1 R (Gas constant)
  c_0      = 1 c_0 (Speed of light)
  h_P      = 1 h_P (Planck constant)
  k_B      = 1 k_B (Boltzmann constant)
  N_A      = 1 N_A (Avogadro constant)
  q_e      = 1 q_e (Elementary charge)
  m_e      = 1 m_e (Electron mass)
  m_p      = 1 m_p (Proton mass)
  G        = 1 G (Newton gravitational constant)
  π        = 1 π (Pi)

The example below uses the relationship c = λν to relate wavelength and frequency, followed by photon energy calculation using E = hν.

[ ]:
# Calculate frequency from wavelength using c = λν
laser_wavelength = Scalar("632.8 nm")  # He-Ne laser
frequency = Scalar("c_0") / laser_wavelength
print(f"He-Ne laser wavelength: {laser_wavelength}")
print(f"Frequency: ν = c/λ = {frequency}")
print(f"Frequency in THz: {frequency.to('THz')}")

# Calculate photon energy
photon_energy = Scalar("h_P") * frequency
print(f"\nPhoton energy: E = hν = {photon_energy}")
print(f"Energy in eV: {photon_energy.to('eV')}")

# Compare different regions of electromagnetic spectrum
uv_wavelength = Scalar("280 nm")
uv_energy = Scalar("h_P * c_0") / uv_wavelength
print(f"\nUV comparison (λ = {uv_wavelength}):")
print(f"UV photon energy: {uv_energy.to('eV')}")
print(f"Energy ratio (UV/visible): {(uv_energy/photon_energy).value:.1f}")
He-Ne laser wavelength: 632.8 nm
Frequency: ν = c/λ = 4.73755e+14 (1/s)
Frequency in THz: 473.755 THz

Photon energy: E = hν = 4.73755e+14 h_P•(1/s)
Energy in eV: 1.9593 eV

UV comparison (λ = 280 nm):
UV photon energy: 4.42801 eV
Energy ratio (UV/visible): 2.3

SITypes supports mathematical functions within unit-aware expressions

[5]:
# Trigonometric functions
ac_voltage = Scalar("sin(45°) * 120 V")
print(f"AC voltage at 45°: {ac_voltage}")

# Square root preserves units correctly
rms_voltage = Scalar("sqrt(2) * 120 V")
print(f"RMS voltage: {rms_voltage}")
AC voltage at 45°: 84.8528 V
RMS voltage: 169.706 V
[6]:
# Exponential and logarithmic functions
decay = Scalar("100 * exp(-ln(2) * 2 s / 5 s)")
print(f"Exponential decay after 2s (half-life 5s): {decay}")

# Circle area using π
circle_area = Scalar("π * (2.5 m)^2")
print(f"Circle area (radius 2.5m): {circle_area}")
Exponential decay after 2s (half-life 5s): 75.7858
Circle area (radius 2.5m): 6.25 π•m^2
[7]:
# Complex engineering calculations
resonance_freq = Scalar("1 / (2 * π * sqrt(1e-3 H * 1e-6 F))")
print(f"LC resonance frequency: {resonance_freq}")

ac_power = Scalar("120 V * 5 A * cos(30°)")
print(f"AC power with 30° phase: {ac_power}")
LC resonance frequency: 5032.92 m^2•s•A/(m^2•s^2•A)
AC power with 30° phase: 519.615 m^2•kg•A/(s^3•A)

Calculation of electron rest mass energy using Einstein’s relation:

\[E = m_e c_0^2\]

where \(m_e\) is the electron rest mass and \(c_0\) is the speed of light in vacuum. SITypes includes these fundamental constants in its database.

[ ]:
# Einstein's mass-energy equivalence: E = mc²
electron_energy = Scalar("m_e * c_0^2")
print(f"E = m_e × c₀² = {electron_energy}")

# Convert to common energy unit
electron_eV = electron_energy.to('eV')
print(f"E = {electron_eV}")
E = m_e × c₀² = 1 m_e•c_0^2
E = 510999 eV

Parallel plate capacitor with dielectric medium:

Given: plate area = 4 cm², separation = 0.15 mm, dielectric constant k = 3.0.

\[C = \frac{k \epsilon_0 A}{d} (n-1)\]

where \(k\) is the dielectric constant, \(\epsilon_0\) is the electric constant (permittivity of free space), \(A\) is the plate area, \(d\) is the separation distance, and \(n\) is the number of plates.

[ ]:
# Parallel plate capacitor calculation
k = Scalar("3.0")                    # dielectric constant
area = Scalar("4 cm^2")             # plate area
separation = Scalar("0.15 mm")      # plate separation
n_plates = Scalar("2")              # number of plates

capacitor_C = k * Scalar("ε_0") * area / separation * (n_plates - 1)
print(f"C = {capacitor_C}")
print(f"C = {capacitor_C.to('pF')} (picofarads)")
C = 7.08335e-16 s^4•A^2/(dm^2•g)
C = 70.8335 pF (picofarads)

SITypes includes databases of atomic weights and molecular properties for chemical calculations

[10]:
# Built-in atomic weights
carbon_weight = Scalar("aw[C]")
hydrogen_weight = Scalar("aw[H]")
oxygen_weight = Scalar("aw[O]")
fe_weight = Scalar("aw[Fe]")
au_weight = Scalar("aw[Au]")

print("Atomic weights from built-in database:")
print(f"Carbon: {carbon_weight}")
print(f"Hydrogen: {hydrogen_weight}")
print(f"Oxygen: {oxygen_weight}")
print(f"Iron: {fe_weight}")
print(f"Gold: {au_weight}")
Atomic weights from built-in database:
Carbon: 12.0107 g/mol
Hydrogen: 1.00794 g/mol
Oxygen: 15.9994 g/mol
Iron: 55.845 g/mol
Gold: 196.967 g/mol
[11]:
# Formula weights and molecular weight calculations
water_mw = Scalar("fw[H2O]")
methane_mw = Scalar("fw[CH4]")
print(f"Water molecular weight: {water_mw}")
print(f"Methane molecular weight: {methane_mw}")

# Calculate molecular weight manually and compare
water_calc = Scalar("2 * aw[H] + aw[O]")
print(f"Water MW (calculated): {water_calc}")
print(f"Verification: {water_calc.value:.6f}{water_mw.value:.6f}")
Water molecular weight: 18.0153 g/mol
Methane molecular weight: 16.0425 g/mol
Water MW (calculated): 18.0153 g/mol
Verification: 18.015280 ≈ 18.015280
[ ]:
# Moles and concentration calculations
sample_mass = Scalar("36 g")
moles_water = sample_mass / water_mw
print(f"Moles in {sample_mass} of water: {moles_water}")

# Concentration calculations
volume_solution = Scalar("250 mL")
molarity = moles_water / volume_solution.to("L")
print(f"Molarity: {molarity.to('mol/L')}")
Moles in 36 g of water: 1.9983 mol
Molarity: 7.99321 mol/L

SITypes provides native support for complex numbers with units

[13]:
# Complex numbers with units for AC circuit analysis
complex_voltage = Scalar("(120+90*I) V")
print(f"Complex voltage: {complex_voltage}")
print(f"Magnitude: {complex_voltage.magnitude}")

# Basic impedance calculation
resistance = Scalar("50 Ω")
reactance = Scalar("30 Ω")
print(f"Resistance: {resistance}")
print(f"Reactance: {reactance}")
Complex voltage: (120) V
Magnitude: 150 V
Resistance: 50 Ω
Reactance: 30 Ω

SITypes enforces dimensional consistency and prevents common calculation errors

[ ]:
# Compatible operations
length1 = Scalar("5 m")
length2 = Scalar("3 ft")
total_length = length1 + length2.to("m")
print(f"Length addition: {length1} + {length2.to('m')} = {total_length}")
print(f"Force × Distance = Energy: {Scalar('10 N')} × {Scalar('2 m')} = {Scalar('10 N') * Scalar('2 m')}")

# Error prevention
try:
    invalid_sum = Scalar("5 m") + Scalar("3 s")  # Can't add length and time
except Exception as e:
    print(f"✓ Prevents length + time: {type(e).__name__}")

try:
    invalid_conversion = Scalar("10 m").to("s")  # Can't convert length to time
except Exception as e:
    print(f"✓ Prevents invalid conversion: {type(e).__name__}")
Length addition: 5 m + 0.9144 m = 5.9144 m
Force × Distance = Energy: 10 N × 2 m = 20 J
✓ Prevents length + time: RMNError
✓ Prevents invalid conversion: ValueError

Summary

This notebook has demonstrated the core capabilities of SITypes for scientific computing:

Key Features:

  • Automatic unit tracking - Eliminates unit-related calculation errors

  • Seamless unit conversions - Supports conversion between compatible unit systems

  • Dimensional consistency - Enforces proper dimensional analysis

  • Mathematical function library - Complete mathematical operations with unit preservation

  • Multi-domain applications - Physics, chemistry, and engineering examples

  • Complex number support - Advanced calculations for AC analysis and other applications

Implementation Benefits:

The examples in this notebook demonstrate actual computational results with proper units automatically derived and verified. This approach reduces the potential for dimensional errors while maintaining computational efficiency.

Further Development:

  • Extend calculations using the demonstrated principles

  • Implement domain-specific algorithms leveraging SITypes

  • Explore the complete mathematical function library

  • Integrate SITypes into larger scientific computing workflows

SITypes provides a robust foundation for unit-aware scientific computation.