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:
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.
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.