Source code for scp.base_fluid

import warnings
from abc import ABC, abstractmethod


[docs] class BaseFluid(ABC): """ A fluid base class that provides convenience methods that can be accessed in derived classes. """ def __init__( self, t_min: float, t_max: float, x: float | None = None, x_min: float | None = None, x_max: float | None = None, ): """ A constructor for a base fluid, that takes a concentration as an argument. Derived classes can decide how to handle the concentration argument and their own constructor interface as needed to construct and manage that specific derived class. @param t_min: Minimum temperature, in degrees Celsius @param t_max: Maximum temperature, in degrees Celsius @param x: Concentration fraction, from 0 to 1 @param x_min: Minimum concentration fraction, from 0 to 1 @param x_max: Maximum concentration fraction, from 0 to 1 """ self._set_temperature_limits(t_min, t_max) if isinstance(x, float) and isinstance(x_min, float) and isinstance(x_max, float): self._set_concentration_limits(x, x_min, x_max) @property @abstractmethod def fluid_name(self) -> str: """ An abstract property that needs to return the fluid name in derived fluid classes Derived function must be decorated with @property @return: string name of the fluid """ def _set_concentration_limits(self, x: float, x_min: float, x_max: float): """ An internal worker function that checks the given concentration against limits, and sets internal variables. @param x: The concentration fraction to check, ranging from 0 to 1 @param x_min: The minimum concentration fraction to allow, ranging from 0 to 1 @param x_max: The maximum concentration fraction to allow, ranging from 0 to 1 @return: Nothing """ if x_min >= x_max: msg = f'Developer error: Fluid "{self.fluid_name}", x_min is greater than x_max' raise ValueError(msg) self.x_min = x_min self.x_max = x_max self.x = self._check_concentration(x) self.x_pct = self.x * 100 def _check_concentration(self, x: float) -> float: """ An internal worker function that checks the given concentration against limits @param x: The concentration to check, in percent @return: A validated concentration value, in percent """ if x < self.x_min: msg = f'Fluid "{self.fluid_name}", concentration must be greater than {self.x_min:0.2f}.\n' msg += f"Resetting concentration to {self.x_min:0.2f}." warnings.warn(msg) return self.x_min elif x > self.x_max: msg = f'Fluid "{self.fluid_name}", concentration must be less than {self.x_max:0.2f}.\n' msg += f"Resetting concentration to {self.x_max:0.2f}." warnings.warn(msg) return self.x_max else: return x def _set_temperature_limits(self, t_min, t_max) -> None: """ A worker function to override the default temperature min/max values @param t_min: The minimum temperature value to allow, in degrees Celsius @param t_max: The maximum temperature value to allow, in degrees Celsius @return: Nothing """ if t_min >= t_max: msg = f'Fluid "{self.fluid_name}", t_min is greater than t_max' raise ValueError(msg) self.t_min = t_min self.t_max = t_max def _check_temperature(self, temp: float) -> float: """ An internal worker function that checks the given temperature against limits @param temp: The temperature to check, in degrees Celsius @return: A validated temperature value, in degrees Celsius """ if temp < self.t_min: msg = f'Fluid "{self.fluid_name}", temperature must be greater than {self.t_min:0.1f}.\n' msg += f"Resetting temperature to {self.t_min:0.1f}." warnings.warn(msg) return self.t_min elif temp > self.t_max: msg = f'Fluid "{self.fluid_name}", temperature must be less than {self.t_max:0.1f}.\n' msg += f"Resetting temperature to {self.t_max:0.1f}." warnings.warn(msg) return self.t_max else: return temp
[docs] @abstractmethod def freeze_point(self, x: float) -> float: """ Abstract method; derived classes should override the freezing point of that fluid @param x: Fluid concentration fraction, ranging from 0 to 1 @return Returns the freezing point of the fluid, in Celsius """
[docs] @staticmethod def freeze_point_units() -> str: return "C"
[docs] @abstractmethod def viscosity(self, temp: float) -> float: """ Abstract method; derived classes should override to return the dynamic viscosity of that fluid. @param temp: Fluid temperature, in degrees Celsius @return: Returns the dynamic viscosity in [Pa-s] """
[docs] @staticmethod def viscosity_units() -> str: return "Pa-s"
[docs] def mu(self, temp: float) -> float: """ Convenience function for returning the dynamic viscosity by the common letter 'mu' @param temp: Fluid temperature, in degrees Celsius @return: Returns the dynamic viscosity -- which one is mu in [Pa-s] """ return self.viscosity(temp)
[docs] @abstractmethod def specific_heat(self, temp: float) -> float: """ Abstract method; derived classes should override to return the specific heat of that fluid. @param temp: Fluid temperature, in degrees Celsius @return: Returns the specific heat in [J/kg-K] """
[docs] @staticmethod def specific_heat_units() -> str: return "J/kg-K"
[docs] def cp(self, temp: float) -> float: """ Convenience function for returning the specific heat by the common shorthand 'cp' @param temp: Fluid temperature, in degrees Celsius @return: Returns the specific heat in [J/kg-K] """ return self.specific_heat(temp)
[docs] @abstractmethod def density(self, temp: float) -> float: """ Abstract method; derived classes should override to return the density of that fluid. @param temp: Fluid temperature, in degrees Celsius @return: Returns the density in [kg/m3] """
[docs] @staticmethod def density_units() -> str: return "kg/m3"
[docs] def rho(self, temp: float) -> float: """ Convenience function for returning the density by the common shorthand 'rho' @param temp: Fluid temperature, in degrees Celsius @return: Returns the density, in [kg/m3] """ return self.density(temp)
[docs] @abstractmethod def conductivity(self, temp: float) -> float: """ Abstract method; derived classes should override to return the thermal conductivity of that fluid. @param temp: Fluid temperature, in degrees Celsius @return: Returns the thermal conductivity in [W/m-K] """
[docs] @staticmethod def conductivity_units() -> str: return "W/m-K"
[docs] def k(self, temp: float) -> float: """ Convenience function for returning the thermal conductivity by the common shorthand 'k' @param temp: Fluid temperature, in degrees Celsius @return: Returns the thermal conductivity, in [W/m-K] """ return self.conductivity(temp)
[docs] def prandtl(self, temp: float) -> float: """ Returns the Prandtl number for this fluid @param temp: Fluid temperature, in degrees Celsius @return: Returns the dimensionless Prandtl number """ return self.cp(temp) * self.mu(temp) / self.k(temp)
[docs] @staticmethod def prandtl_units() -> str: return "-"
[docs] def pr(self, temp: float = 0.0) -> float: """ Convenience function for returning the Prandtl number by the common shorthand 'pr' @param temp: Fluid temperature, in degrees Celsius @return: Returns the dimensionless Prandtl number """ return self.prandtl(temp)
[docs] def thermal_diffusivity(self, temp: float) -> float: """ Returns the thermal diffusivity for this fluid @param temp: Fluid temperature, in degrees Celsius @return: Returns the thermal diffusivity in [m2/s] """ return self.k(temp) / (self.rho(temp) * self.cp(temp))
[docs] @staticmethod def thermal_diffusivity_units() -> str: return "m2/s"
[docs] def alpha(self, temp: float) -> float: """ Convenience function for returning the thermal diffusivity by the common shorthand 'alpha' @param temp: Fluid temperature, in degrees Celsius @return: Returns the thermal diffusivity in [m2/s] """ return self.thermal_diffusivity(temp)