Units and Scaling¶
The scaling module provides units and scaling capabilities.
Creating Quantities¶
- underworld3.quantity(value, units=None)[source]¶
Create a unit-aware quantity.
- Parameters:
- Returns:
Unit-aware quantity
- Return type:
Examples
>>> viscosity = uw.quantity(1e21, "Pa*s") >>> velocity = uw.quantity(5, "cm/year") >>> dT = uw.quantity(1000, "K") - uw.quantity(273, "K")
- underworld3.expression(name, *args, _unique_name_generation=False, **kwargs)¶
A SymPy Symbol that wraps a value for lazy evaluation.
UWexpression is a named symbolic placeholder. When used in SymPy expressions, it acts as a Symbol. At evaluation time, the wrapped value is substituted.
Key Design (Simplified 2025-11): - Inherits from Symbol for SymPy compatibility - Does NOT inherit from UWQuantity (expressions don’t have units themselves) - Units are discovered from the wrapped thing when needed - Arithmetic returns pure SymPy expressions
Symbol Disambiguation (2025-12): - Uses _hashable_content() override (like sympy.Dummy) for uniqueness - Clean display names without invisible whitespace hacks - Symbols with same name but different _uw_id are distinct
- Parameters:
Examples
>>> alpha = uw.expression(r"\alpha", uw.quantity(3e-5, "1/K")) >>> rho0 = uw.expression(r"\rho_0", uw.quantity(3300, "kg/m^3")) >>> >>> # Symbolic multiplication >>> product = rho0 * alpha # Returns SymPy Mul >>> >>> # Wrap the product for lazy evaluation >>> combo = uw.expression(r"\rho_0 \alpha", product)
Unit Conversion¶
- underworld3.get_units(expression, simplify=False)[source]¶
Get the units of an expression or quantity.
This is the unified, public API for extracting units from any object type (variables, quantities, SymPy expressions, etc.). It replaces the previous units_of() function and the internal function.unit_conversion.get_units() for a clean, single API surface.
IMPORTANT: This function ALWAYS returns Pint Unit objects (or None), never strings. We accept strings for INPUT (user convenience), but always return Pint objects.
- Args:
expression: Expression, quantity, or unit-aware object simplify: If True, simplify mixed units to base SI (default False).
- Returns:
Pint Unit object or None if no units
- Examples:
>>> velocity = uw.discretisation.MeshVariable("velocity", mesh, 2, units="m/s") >>> units = uw.get_units(velocity) >>> print(units) # <Unit('meter / second')>
>>> # Mixed units from composite expressions >>> th2 = uw.expression("th2", ((2 * kappa * t_now))**0.5) >>> uw.get_units(th2) # megayear ** 0.5 * meter / second ** 0.5 >>> uw.get_units(th2, simplify=True) # meter (simplified!)
- underworld3.convert_units(quantity, target_units)[source]¶
Convert quantity to different units.
This is the SINGLE SOURCE OF TRUTH for unit conversion in UW3. All .to() methods on unit-aware types should delegate to this function.
Handles: - UWQuantity → returns new UWQuantity with converted value - UWexpression → returns new UWexpression with converted value - UnitAwareArray → returns new UnitAwareArray with converted values - Pint Quantity → returns converted Pint Quantity
- Args:
quantity: Quantity to convert (UWQuantity, UWexpression, UnitAwareArray, Pint) target_units: Target units for conversion (str or Pint Unit)
- Returns:
Same type as input, converted to target units
- Raises:
DimensionalityError: If units are not compatible for conversion NoUnitsError: If quantity has no units
- Examples:
>>> velocity = uw.quantity(10, "m/s") >>> velocity_kmh = uw.convert_units(velocity, "km/h") >>> print(velocity_kmh) # 36.0 [kilometer / hour]
>>> radius = uw.expression("r", uw.quantity(6370, "km")) >>> radius_m = uw.convert_units(radius, "m") >>> print(radius_m.value) # 6370000.0
- underworld3.to_base_units(quantity)[source]¶
Convert quantity to SI base units.
This is a convenience function that converts any unit-aware quantity to its SI base unit representation.
- Args:
quantity: Quantity to convert (UWQuantity, UWexpression, UnitAwareArray, Pint)
- Returns:
Same type as input, converted to SI base units
- Raises:
NoUnitsError: If quantity has no units
- Examples:
>>> velocity = uw.quantity(36, "km/h") >>> velocity_si = uw.to_base_units(velocity) >>> print(velocity_si) # 10.0 [meter / second]
>>> radius = uw.expression("r", uw.quantity(6370, "km")) >>> radius_si = uw.to_base_units(radius) >>> print(radius_si.value) # 6370000.0
- Return type:
- underworld3.to_compact(quantity)[source]¶
Convert quantity to most human-readable unit representation.
This automatically chooses unit prefixes (kilo, mega, micro, etc.) to make the number more readable. For example, 0.001 km becomes 1 m.
- Args:
quantity: Quantity to make compact (UWQuantity, UWexpression, UnitAwareArray, Pint)
- Returns:
Same type as input, with compact units
- Raises:
NoUnitsError: If quantity has no units
- Examples:
>>> length = uw.quantity(0.001, "km") >>> length_compact = uw.to_compact(length) >>> print(length_compact) # 1.0 [meter]
>>> big_length = uw.quantity(1e9, "m") >>> big_compact = uw.to_compact(big_length) >>> print(big_compact) # 1.0 [gigameter]
- Return type:
Non-dimensionalisation¶
- underworld3.non_dimensionalise(expression, model=None)[source]¶
Convert expression to non-dimensional form using model reference scales.
This function uses dimensional analysis to compute appropriate scaling factors from the model’s reference quantities, then divides the expression by those scales to produce dimensionless values. Dimensionality information is preserved to enable re-dimensionalization.
Protocol-based approach works with: - MeshVariable/SwarmVariable (via .non_dimensional_value() method) - UWQuantity objects (extracts dimensionality, computes scale) - UnitAwareArray (extracts dimensionality from units) - Plain numbers (pass through unchanged)
- Args:
expression: Expression, quantity, or unit-aware object to non-dimensionalise model: Model instance with reference quantities (uses default if None)
- Returns:
Non-dimensional value(s) with preserved dimensionality metadata
- Raises:
NoUnitsError: If expression has no units and model has reference quantities ValueError: If model has no reference quantities
- Examples:
>>> # With variables (uses existing method) >>> velocity_var = MeshVariable("v", mesh, 2, units="m/s") >>> nondim_v = non_dimensionalise(velocity_var)
>>> # With UWQuantity >>> velocity_qty = uw.quantity(5.0, "cm/year") >>> nondim_qty = non_dimensionalise(velocity_qty, model) >>> # Result is dimensionless but remembers it was velocity
>>> # With plain number (no model reference quantities) >>> plain_value = 2.5 >>> result = non_dimensionalise(plain_value) # Returns 2.5
- Return type:
- underworld3.dimensionalise(expression, target_dimensionality=None, model=None)[source]¶
Restore dimensional form to non-dimensional values using model reference scales.
This is the companion function to non_dimensionalise(). It multiplies dimensionless values by the appropriate reference scale to restore their dimensional form.
The function can operate in two modes: 1. Auto mode: Extract dimensionality from the expression itself (if preserved) 2. Explicit mode: Use provided target_dimensionality
- Parameters:
expression (UWQuantity, UnitAwareArray, or number) – Non-dimensional value with preserved dimensionality metadata.
target_dimensionality (dict, optional) – Target dimensionality in Pint format, e.g.
{'[length]': 1, '[time]': -1}for velocity. If None, uses dimensionality from the expression.model (Model, optional) – Model instance with reference quantities. Uses default if None.
- Returns:
Dimensional quantity with appropriate units.
- Return type:
quantity
- Raises:
ValueError – If no dimensionality information is available.
ValueError – If model has no reference quantities.
Examples
Auto mode – dimensionality preserved from
non_dimensionalise():>>> velocity_qty = uw.quantity(5.0, "cm/year") >>> nondim_vel = non_dimensionalise(velocity_qty, model) >>> dimensional_vel = dimensionalise(nondim_vel, model=model)
Explicit mode – specify dimensionality:
>>> plain_value = 2.5 >>> velocity_dimensionality = {'[length]': 1, '[time]': -1} >>> velocity = dimensionalise(plain_value, velocity_dimensionality, model)
Dimensional Analysis¶
- underworld3.get_dimensionality(expression)[source]¶
Get the dimensionality of an expression or quantity.
- Args:
expression: Expression, quantity, or unit-aware object
- Returns:
Dimensionality representation (backend-specific) or None if no units
- Examples:
>>> velocity = EnhancedMeshVariable("velocity", mesh, 2, units="m/s") >>> dims = get_dimensionality(velocity) >>> print(dims) # [length] / [time]
- Return type:
Any | None