Source code for calculation.medium

from traits.api import HasTraits, Float, Range, TraitError, Union
from traitsui.api import View, Item, Group
import numpy as np

[docs] class Medium(HasTraits): """ Represents the physical properties of the medium (typically air) used in simulations. Automatically calculates density, speed of sound, and kinematic viscosity based on temperature and humidity if not explicitly provided. Attributes: temperature_celsius (float): Ambient temperature in °C (-50 to 60). rel_humidity (float): Relative humidity as a value between 0 and 1. density (float): Air density in kg/m³ (calculated or provided). speed_of_sound (float): Speed of sound in m/s (calculated or provided). c (float): Alias for speed_of_sound. temperature_kelvin (float): Temperature in Kelvin. kinematic_viscosity (float): Kinematic viscosity of air in m²/s. """ # --- Input Parameter mit Traits Validierung --- temperature_celsius = Range(-50.0, 60.0, 20.0) rel_humidity = Range(0.0, 1.0, 0.5) density = Union(None, Float(min=0.0), value=None) # kg/m³ speed_of_sound = Union(None, Float(min=0.0)) # m/s # --- Automatisch berechnete Eigenschaften --- temperature_kelvin = Float kinematic_viscosity = Float c = Float # Alias für speed_of_sound def __init__(self, **kwargs): """ Initialize a Medium object with temperature and humidity. If `density` or `speed_of_sound` is not provided, they are calculated automatically. Raises: TraitError: If provided density or speed of sound is non-positive. """ super().__init__(**kwargs) self.temperature_kelvin = self.temperature_celsius + 273.15 if self.density is None: self.calc_density() elif self.density <= 0: raise TraitError("Density must be positive.") if self.speed_of_sound is None: self.calc_speed_of_sound() elif self.speed_of_sound <= 0: raise TraitError("speed of sound must be positive.") else: self.c = self.speed_of_sound self.calc_kinematic_viscosity()
[docs] def calc_density(self): """ Calculates air density using the Magnus equation. The density is calculated as: .. math:: \\rho = \\frac{p - p_v}{R_d \\, T} + \\frac{p_v}{R_v \\, T} where: - :math:`p` atmospheric pressure (Pa) - :math:`p_v = \\phi \\; p_{\\mathrm{sat}}` partial vapor pressure (Pa) - :math:`p_{\\mathrm{sat}} = 6.112 \\, \\exp\\biggl(\\frac{17.62 \\, T}{243.12 + T}\\biggr) \\times 100` (Pa) - :math:`\\phi` relative humidity (0…1) - :math:`T` absolute temperature in Kelvin - :math:`R_d = 287.05 \\; \\mathrm{J/(kg \\cdot K)}` gas constant for dry air - :math:`R_v = 461.5 \\; \\mathrm{J/(kg \\cdot K)}` gas constant for water vapor Raises: TraitError: If the result is non-positive. """ p = 1013.15 * 100 # Atmospheric pressure in Pa T = self.temperature_kelvin phi = self.rel_humidity R_d = 287.05 # Gas constant for dry air R_v = 461.5 # Gas constant for water vapor p_sat = 6.112 * np.exp(17.62 * T / (243.12 * T)) * 100 p_v = phi * p_sat rho = (p - p_v) / (R_d * T) + p_v / (R_v * T) if rho <= 0: raise TraitError("Calculated density must be > 0.") self.density = rho
[docs] def calc_speed_of_sound(self): """ Approximates the speed of sound based on DIN ISO 9613-1:1993. The formula used is: .. math:: c = 331.3 + 0.606 \\,T + 0.0124 \\,\phi where: - :math:`T` ambient temperature in °C - :math:`\phi` relative humidity (0…1) - :math:`c` speed of sound in m/s """ self.c = 331.3 + 0.606 * self.temperature_celsius + 0.0124 * self.rel_humidity
[docs] def calc_kinematic_viscosity(self): r""" Calculates the kinematic viscosity of air using Sutherland's formula. The dynamic viscosity :math:\mu is calculated using: .. math:: \mu = \mu_0 \left( \frac{T}{T_0} \right)^{3/2} \cdot \frac{T_0 + C}{T + C} where: - :math:\mu_0 = 1.716 \times 10^{-5}\ \text{Pa·s} (reference viscosity), - :math:T_0 = 273.15\ \text{K} (reference temperature), - :math:C = 111\ \text{K} (Sutherland's constant), - :math:T temperature in Kelvin. The kinematic viscosity :math:\nu is then: .. math:: \nu = \frac{\mu}{\rho} where :math:\rho air density in kg/m³. """ T = self.temperature_kelvin mu0 = 1.716e-5 # Reference dynamic viscosity (Pa·s) T0 = 273.15 # Reference temperature (K) C = 111 # Sutherland's constant for air mu = mu0 * ((T / T0) ** 1.5) * ((T0 + C) / (T + C)) self.kinematic_viscosity = mu / self.density
[docs] def to_dict(self): """ Converts the medium's properties to a dictionary. Returns: dict: Dictionary containing all relevant physical parameters. """ return { "temperature_celsius": self.temperature_celsius, "temperature_kelvin": self.temperature_kelvin, "rel_humidity": self.rel_humidity, "density": self.density, "speed_of_sound": self.c, "kinematic_viscosity": self.kinematic_viscosity }
[docs] @classmethod def from_dict(cls, data): """ Creates a Medium instance from a dictionary. Args: data (dict): Dictionary with keys matching Medium attributes. Returns: Medium: A new Medium instance. """ return cls( temperature_celsius=data['temperature_celsius'], rel_humidity=data['rel_humidity'], density=data.get('density'), speed_of_sound=data.get('speed_of_sound'))
# TraitsUI View traits_view = View( Group( Item('temperature_celsius', label="Temperatur (°C)"), Item('rel_humidity', label="Relative Luftfeuchtigkeit"), Item('density', label="Dichte (kg/m³)", style='readonly'), Item('speed_of_sound', label="Schallgeschwindigkeit (m/s)", style='readonly'), Item('kinematic_viscosity', label="Kinematische Viskosität (m²/s)", style='readonly'), ), title="Medium Eigenschaften", buttons=['OK', 'Cancel'], resizable=True )
if __name__ == "__main__": medium = Medium() medium.configure_traits()