CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-scipp

Multi-dimensional data arrays with labeled dimensions for scientific computing

Pending
Overview
Eval results
Files

units-system.mddocs/

Units System

Comprehensive physical unit system with predefined units, unit conversion, arithmetic operations, and alias management. Scipp's unit system provides automatic unit propagation through all operations, ensuring dimensional consistency and preventing common scientific computing errors.

Capabilities

Unit Class

Core unit representation with arithmetic operations and string parsing.

class Unit:
    """Physical unit with arithmetic operations and parsing"""
    
    def __init__(self, unit_string):
        """
        Create Unit from string representation
        
        Args:
            unit_string (str): Unit string (e.g., 'm', 'kg*m/s^2', 'mm/s')
            
        Examples:
            Unit('m')        # meter
            Unit('kg*m/s^2') # force unit (Newton)
            Unit('mm')       # millimeter
            Unit('1/s')      # frequency unit
        """
    
    def __mul__(self, other):
        """Multiply units: m * s -> m*s"""
    
    def __truediv__(self, other):
        """Divide units: m / s -> m/s"""
    
    def __pow__(self, exponent):
        """Raise unit to power: m^2 for area"""
    
    def __eq__(self, other):
        """Check unit equality"""
    
    def __str__(self):
        """String representation of unit"""
    
    def __repr__(self):
        """Detailed string representation"""

Unit Conversion

Functions for converting between compatible units and checking dimensional consistency.

def to_unit(x, unit):
    """
    Convert variable to specified unit
    
    Args:
        x (Variable or DataArray): Input with units
        unit (Unit or str): Target unit
        
    Returns:
        Variable or DataArray: Converted to target unit
        
    Raises:
        UnitError: If units are incompatible
    """

Predefined Units

Common physical units available as module constants.

# Dimensionless
dimensionless: Unit  # Dimensionless quantity
one: Unit           # Alias for dimensionless

# Length units
m: Unit         # meter
mm: Unit        # millimeter  
angstrom: Unit  # angstrom (10^-10 m)

# Time units
s: Unit     # second
us: Unit    # microsecond
ns: Unit    # nanosecond

# Mass units
kg: Unit    # kilogram

# Temperature units
K: Unit     # kelvin

# Angle units
rad: Unit   # radian
deg: Unit   # degree

# Energy units
meV: Unit   # millielectronvolt

# Count units
counts: Unit    # count unit for discrete quantities

# Special units
default_unit: Unit  # Marker for default unit behavior

Unit Aliases

Management system for custom unit aliases and shortcuts.

class UnitAliases:
    """Manager for unit aliases and shortcuts"""
    
    def __setitem__(self, alias, unit):
        """
        Define a new unit alias
        
        Args:
            alias (str): Alias name
            unit (str or Unit or Variable): Unit definition
            
        Raises:
            ValueError: If unit already has an alias
        """
    
    def __delitem__(self, alias):
        """Remove an existing alias"""
    
    def clear(self):
        """Remove all aliases"""
    
    def scoped(self, **kwargs):
        """
        Context manager for temporary aliases
        
        Args:
            **kwargs: Mapping from alias names to units
            
        Returns:
            Context manager for temporary aliases
        """
    
    def keys(self):
        """Iterator over alias names"""
    
    def values(self):
        """Iterator over aliased units"""
    
    def items(self):
        """Iterator over (alias, unit) pairs"""

# Global alias manager instance
aliases: UnitAliases

Usage Examples

Basic Unit Operations

import scipp as sc

# Create variables with units
length = sc.scalar(5.0, unit='m')
time = sc.scalar(2.0, unit='s')

# Unit arithmetic through operations
velocity = length / time  # Automatically gets 'm/s' unit
area = length * length    # Automatically gets 'm^2' unit

# Check units
print(velocity.unit)  # 'm/s'
print(area.unit)      # 'm^2'

# Unit compatibility checking
try:
    length + time  # Will raise UnitError - incompatible units
except sc.UnitError as e:
    print(f"Cannot add length and time: {e}")

Working with Predefined Units

# Use predefined units
distance = sc.array(dims=['x'], values=[1, 2, 3], unit=sc.units.m)
temperature = sc.array(dims=['sensor'], values=[273, 298, 373], unit=sc.units.K)

# Angle calculations with proper units
angles = sc.linspace('angle', 0, 2*3.14159, 100, unit=sc.units.rad)
angles_deg = sc.linspace('angle', 0, 360, 100, unit=sc.units.deg)

# Convert between angle units
angles_converted = sc.to_unit(angles_deg, sc.units.rad)

# Energy units for scientific applications
energies = sc.array(dims=['detector'], values=[1, 5, 10, 50], unit=sc.units.meV)

# Counting statistics
detector_counts = sc.array(dims=['bin'], values=[100, 150, 80], unit=sc.units.counts)

Unit Conversion

# Convert between compatible units
length_m = sc.scalar(1000, unit='mm')
length_converted = sc.to_unit(length_m, 'm')  # Result: 1.0 m

# Convert complex units
force = sc.scalar(10, unit='kg*m/s^2')  # Newton
force_in_base = sc.to_unit(force, 'kg*m/s^2')  # Same unit

# Temperature conversion (if supported)
temp_celsius = sc.scalar(25, unit='degC')
# temp_kelvin = sc.to_unit(temp_celsius, 'K')  # Would be 298.15 K

Custom Unit Aliases

# Define custom aliases for convenience
sc.units.aliases['speed'] = 'm/s'
sc.units.aliases['pressure'] = 'kg/(m*s^2)'

# Use aliases in calculations
velocity = sc.scalar(10, unit='speed')
print(velocity.unit)  # Will display as 'speed'

# Temporary aliases with context manager
with sc.units.aliases.scoped(temp='K', dist='mm'):
    temperature = sc.scalar(300, unit='temp')
    position = sc.scalar(5.2, unit='dist')
    
# Aliases are automatically removed after context

Advanced Unit Manipulations

# Create complex derived units
acceleration = sc.scalar(9.81, unit='m/s^2')
mass = sc.scalar(2.0, unit='kg')
force = mass * acceleration  # Result: kg*m/s^2 (Newton)

# Work with dimensionless quantities
ratio = sc.scalar(0.75, unit=sc.units.dimensionless)
percentage = ratio * 100  # Still dimensionless

# Unit exponentiation
volume = sc.pow(length, 3)  # m^3
print(volume.unit)  # 'm^3'

# Complex unit expressions
power = force * velocity  # kg*m^2/s^3 (Watt)
energy = power * time     # kg*m^2/s^2 (Joule)

Scientific Units in Practice

import numpy as np

# Neutron scattering data with proper units
wavelength = sc.array(dims=['detector'], values=[1.8, 2.0, 2.2], unit=sc.units.angstrom)
energy = sc.array(dims=['detector'], values=[25.3, 20.4, 16.7], unit=sc.units.meV)

# Scattering angle calculation
scattering_angles = sc.linspace('angle', 0, 180, 181, unit=sc.units.deg)
q_vector = 4 * sc.sin(scattering_angles / 2) / wavelength  # Momentum transfer

# Time-of-flight calculations
distance = sc.scalar(10.0, unit=sc.units.m)  # Sample-detector distance
velocity = sc.sqrt(2 * energy / sc.scalar(1.67e-27, unit='kg'))  # Neutron velocity
time_of_flight = distance / velocity  # Automatically in seconds

# Statistical analysis with count data
raw_counts = sc.array(dims=['bin'], values=[120, 98, 156, 89], unit=sc.units.counts)
measurement_time = sc.scalar(300, unit=sc.units.s)
count_rate = raw_counts / measurement_time  # counts/s

# Uncertainty propagation with units
count_uncertainty = sc.sqrt(raw_counts)  # Poisson statistics
rate_uncertainty = count_uncertainty / measurement_time  # Propagated uncertainty

Unit Error Handling

# Unit compatibility checking
try:
    length = sc.scalar(5, unit='m')
    time = sc.scalar(2, unit='s')
    invalid = length + time  # Incompatible units
except sc.UnitError as e:
    print(f"Unit error: {e}")

# Dimensionless function requirements
try:
    angle_with_units = sc.scalar(1.57, unit='rad')
    result = sc.exp(angle_with_units)  # Should fail - exp requires dimensionless
except sc.UnitError as e:
    print(f"Function requires dimensionless input: {e}")

# Correct usage
dimensionless_value = sc.scalar(1.57, unit=sc.units.dimensionless)
result = sc.exp(dimensionless_value)  # Works correctly

Install with Tessl CLI

npx tessl i tessl/pypi-scipp

docs

array-creation.md

binning-histogramming.md

coordinate-systems.md

core-data-structures.md

index.md

input-output.md

mathematical-operations.md

reduction-operations.md

scipy-integration.md

shape-operations.md

spatial-operations.md

testing-utilities.md

units-system.md

visualization.md

tile.json