def from_abstract_state(cls, state: CoolProp.AbstractState): new_state = cls(state.backend_name(), '&'.join(state.fluid_names())) # Uses mass fraction to work with incompressible fluids masses = state.get_mass_fractions() if len(masses) > 1: new_state.set_mass_fractions(masses) try: rho = state.rhomolar() T = state.T() new_state.update(CoolProp.DmolarT_INPUTS, rho, T) except: pass return new_state
class Fluid: """Represents a fluid.""" def __init__(self, name: str, eos: str = 'HEOS'): """Initiate a Fluid instance. :param ID: id of fluid """ self.name = name self.eos = eos.upper() self.state = AbstractState(self.eos, self.name) if self.state.name() not in ["NitrousOxide"]: raise NotImplementedError( f'{self.state.name()} is not supported currently') self.Tmax = 309.5 # self.state.Tmax() self.Tmin = 182.23 # self.state.Tmin() self.pmax = self.state.pmax() self.pmin = 0 def copy(self): fluid = Fluid(self.name, self.eos) fluid.set_state(P=self.state.p(), T=self.state.T()) return fluid def set_state(self, D: float = None, P: float = None, T: float = None, Q: float = None, H: float = None, S: float = None, U: float = None): args_present = { 'D': D is not None, 'P': P is not None, 'T': T is not None, 'Q': Q is not None, 'H': H is not None, 'S': S is not None, 'U': U is not None } if sum(args_present.values()) != 2: raise ValueError( f'Must have exactly 2 arguments: {sum(args_present.values())} provided' ) args = [] if args_present['D']: if args_present['P']: args = CP.DmassP_INPUTS, D, P elif args_present['T']: args = CP.DmassT_INPUTS, D, T elif args_present['Q']: args = CP.DmassQ_INPUTS, D, Q elif args_present['H']: args = CP.DmassHmass_INPUTS, D, H elif args_present['S']: args = CP.DmassSmass_INPUTS, D, S elif args_present['U']: args = CP.DmassUmass_INPUTS, D, U elif args_present['P']: if args_present['T']: args = CP.PT_INPUTS, P, T elif args_present['Q']: args = CP.PQ_INPUTS, P, Q elif args_present['H']: args = CP.HmassP_INPUTS, H, P elif args_present['S']: args = CP.PSmass_INPUTS, P, S elif args_present['U']: args = CP.PUmass_INPUTS, P, U elif args_present['T']: if args_present['Q']: args = CP.QT_INPUTS, Q, T elif args_present['H']: args = CP.HmassT_INPUTS, H, T elif args_present['S']: args = CP.SmassT_INPUTS, S, T elif args_present['U']: args = CP.TUmass_INPUTS, T, U elif args_present['Q']: if args_present['H']: args = CP.HmassQ_INPUTS, H, Q elif args_present['S']: args = CP.QSmass_INPUTS, Q, S elif args_present['U']: raise ValueError('Invalid combination: Q and U') elif args_present['H']: if args_present['S']: args = CP.HmassSmass_INPUTS, H, S elif args_present['U']: raise ValueError('Invalid combination: H and U') elif args_present['S'] and args_present['U']: args = CP.SmassUmass_INPUTS, S, U else: raise ValueError('Invalid combination') try: self.state.update(*args) except ValueError: pass def Vf(self, S: float): x = self.chi() return 1 / (1 / (1 + S * ((1 - x) / x) * self.rhog([self.state.T()])[0] / self.rhol([self.state.T()])[0])) def chi(self): x = self.state.Q() if x >= 0: return x if self.state.rhomass() > self.rhol([self.state.T()])[0]: return 0 else: return 1 def viscosityl(self, T): b1 = 1.6089 b2 = 2.0439 b3 = 5.24 b4 = 0.0293423 theta = (self.state.T_critical() - b3) / (T - b3) return b4 * np.exp(b1 * (theta - 1)**(1 / 3) + b2 * (theta - 1)**(4 / 3)) def viscosityg(self, T): b1 = 3.3281 b2 = -1.18237 b3 = -0.055155 Tr = T / self.state.T_critical() return 0.001 * np.exp(b1 + b2 * (1 / Tr - 1)**(1 / 3) + b3 * (1 / Tr - 1)**(4 / 3)) if ( self.Tmin < T < self.Tmax) else None def viscosity(self): T = self.state.T() mug = self.viscosityg(T) mul = self.viscosityl(T) x = self.chi() rho = self.state.rhomass() rhol = self.rhol([T])[0] rhog = self.rhog([T])[0] return mug * x * rho / rhog + mul * (1 - x) * rho / rhol def dvg_dP_saturation(self): dP = 0.002 rho1 = PropsSI('D', 'P', self.state.p() + dP / 2, 'Q', 1, self.name) rho0 = PropsSI('D', 'P', self.state.p() - dP / 2, 'Q', 1, self.name) dvg = 1 / rho1 - 1 / rho0 return dvg / dP def rhol(self, T: Iterable): return [ PropsSI('D', 'T', t, 'Q', 0, self.eos + "::" + self.name) for t in T ] def rhog(self, T: Iterable): return [ PropsSI('D', 'T', t, 'Q', 1, self.eos + "::" + self.name) for t in T ] def psat(self, T: Iterable): return [ PropsSI('P', 'Q', 0.5, 'T', t, self.eos + "::" + self.name) if (self.Tmin < t < self.Tmax) else None for t in T ] def tsat(self, P: Iterable): return [ PropsSI('T', 'P', P, 'Q', 0.5, self.eos + "::" + self.name) if (self.pmin < p < self.pmax) else None for p in P ] def hl(self, T: Iterable): return [ PropsSI('H', 'T', t, 'Q', 0, self.eos + "::" + self.name) if (self.Tmin < t < self.Tmax) else None for t in T ] def hg(self, T: Iterable): return [ PropsSI('H', 'T', t, 'Q', 1, self.eos + "::" + self.name) if (self.Tmin < t < self.Tmax) else None for t in T ] def sl(self, T: Iterable): return [ PropsSI('S', 'T', t, 'Q', 0, self.eos + "::" + self.name) if (self.Tmin < t < self.Tmax) else None for t in T ] def sg(self, T: Iterable): return [ PropsSI('S', 'T', t, 'Q', 1, self.eos + "::" + self.name) if (self.Tmin < t < self.Tmax) else None for t in T ] def __repr__(self): return f'Fluid({self.name}: p={self.state.p() / 100000:.1f}bar, t={self.state.T():.1f}K)'