#####################################################################
# DOC #
#####################################################################
"""
@author: F. Ramognino <federico.ramognino@polimi.it>
Last update: 12/06/2023
"""
#####################################################################
# IMPORT #
#####################################################################
from __future__ import annotations
from typing import Self
from collections.abc import Iterable
from .HeatTransferModel import HeatTransferModel
from libICEpost.src.engineModel.EngineModel import EngineModel
#############################################################################
# MAIN CLASSES #
#############################################################################
#Woschni model to compute wall heat transfer coefficient:
[docs]
class Woschni(HeatTransferModel):
"""
Class for computation of wall heat transfer with Woschni model:
h = C1 * (p/1000.)^.8 * T^(-0.53) * D^(-0.2) * uwos^(0.8) \\
C2Prime = C2 + C2corr * (u'/upMean) \\
uwos = C2Prime * upMean + C3 * (p - p_mot) * Vs * T0 / (p0 * V0) \\
p_mot = p * ( V0 / V )**nwos
Vs: Displacement volume
upMean: Mean piston speed
Where:
1) C2 changes depending if at closed-valves (C2cv) or during gas-exchange (C2ge)
2) C3 changes depending if during compression (C3comp) or during combustion/expansion (C3comb)
3) Reference conditions (0) are at IVC or startTime if it is in closed-valve region.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Attibutes:
coeffs: dict
Container for model constants
"""
#########################################################################
#Class methods:
[docs]
@classmethod
def fromDictionary(cls, dictionary:dict) -> Woschni:
"""
Construct from dictionary.
Args:
dictionary (dict): the input dictionary, containing:
nwos (float, default 1.32)
C1 (float, default 3.26)
C2cv (float, default 2.28)
C2ge (float, default 6.18)
C2corrcv(float, default 0.308)
C2corrge(float, default 0.417)
C3comp (float, default 0.0)
C3comb (float, default 3.24e-3)
useTurbulence (bool, False)
Returns:
Woschni: Instance of this class
"""
args = ["nwos", "C1", "C2cv", "Cge", "C2corrcv", "C2corrge", "C3comp", "C3comb", "useTurbulence"]
inputDict = {var:dictionary[var] for var in args if var in dictionary}
return cls(**inputDict)
#########################################################################
#Constructor:
def __init__(self, /,
*,
nwos:float=1.32,
C1:float=3.26,
C2cv:float=2.28,
C2ge:float=6.18,
C2corrcv:float=0.308,
C2corrge:float=0.417,
C3comp:float=0.0,
C3comb:float=3.24e-3,
useTurbulence:bool=False):
"""
Initialize the parameters required by Woschni model.
h = C1 * (p/1000.)^.8 * T^(-0.53) * D^(-0.2) * uwos^(0.8) \\
C2Prime = C2 + C2corr * (u'/upMean) \\
uwos = C2Prime * upMean + C3 * (p - p_mot) * Vs * T0 / (p0 * V0) \\
p_mot = p * ( V0 / V )**nwos
Vs: Displacement volume
upMean: Mean piston speed
Where:
1) C2 changes depending if at closed-valves (C2cv) or during gas-exchange (C2ge)\\
2) C3 changes depending if during compression (C3comp) or during combustion/expansion (C3comb)\\
3) Reference conditions (0) are at IVC or startTime if it is in closed-valve region.\\
4) C2corr changes depending if at closed-valves (C2corrcv) or during gas-exchange (C2corrge)
Args:
nwos (float, optional): Defaults to 1.32.
C1 (float, optional): Defaults to 3.26.
C2cv (float, optional): Defaults to 2.28.
C2ge (float, optional): Defaults to 6.18.
C3comp (float, optional): Defaults to 0.0.
C3comb (float, optional): Defaults to 3.24e-3.
useTurbulence (bool, optional): Use the turbulence effect? Need to estimate the turbulent velocity fluctuation (u'). Defaults to False.
"""
self.coeffs = \
{
"nwos" : nwos ,
"C1" : C1 ,
"C2cv" : C2cv ,
"C2ge" : C2ge ,
"C2corrcv" : C2corrcv ,
"C2corrge" : C2corrge ,
"C3comp" : C3comp ,
"C3comb" : C3comb ,
"useTurbulence": useTurbulence ,
}
#Check types
for c in self.coeffs:
if c == "useTurbulence":
self.checkType(self.coeffs[c], bool, c)
else:
self.checkType(self.coeffs[c], float, c)
#########################################################################
#Cumpute wall heat transfer:
[docs]
def h(self, *, engine:EngineModel.EngineModel, CA:float|Iterable|None=None, **kwargs) -> float:
"""
Compute convective wall heat transfer with Woschni correlation:
h = C1 * (p/1000.)^.8 * T^(-0.53) * D^(-0.2) * uwos^(0.8) \\
C2Prime = C2 + C2corr * (u'/upMean) \\
uwos = C2Prime * upMean + C3 * (p - p_mot) * Vs * T0 / (p0 * V0) \\
p_mot = p * ( V0 / V )**nwos
Vs: Displacement volume
upMean: Mean piston speed
Where:
1) C2 changes depending if at closed-valves (C2cv) or during gas-exchange (C2ge)
2) C3 changes depending if during compression (C3comp) or during combustion/expansion (C3comb)
3) Reference conditions (0) are at IVC or startTime if it is in closed-valve region.
4) C2corr changes depending if at closed-valves (C2corrcv) or during gas-exchange (C2corrge)
Args:
engine (EngineModel): The engine model from which taking data.
CA (float | Iterable | None, optional): Time for which computing heat transfer. If None, uses engine.time.time. Defaults to None.
Returns:
float: convective wall heat transfer coefficient [W/(m^2 K)]
"""
#Check arguments:
self.checkType(engine,EngineModel.EngineModel,"engine")
if not CA is None:
self.checkType(CA,(float, Iterable),"CA")
CA = engine.time.time if CA is None else CA
p = engine.data.p(CA)
T = engine.data.T(CA)
geometry = engine.geometry
#Compute heat transfer coefficient:
uwos = self.uwos(CA=CA, engine=engine)
h = self.coeffs["C1"] * ((p/1000.)**0.8) * (T**(-0.53)) * (geometry.D**(-0.2)) * (uwos**0.8)
return h
#########################################################################
#Compute uwos:
[docs]
def uwos(self, engine:EngineModel.EngineModel, *, CA:float|Iterable|None=None) -> float:
"""
uwos = C2Prime * upMean + C3 * (p - p_mot) * Vs * T0 / (p0 * V0) \\
C2Prime = C2 + C2corr * (u'/upMean) \\
p_mot = p * ( V0 / V )**nwos
Vs: Displacement volume
upMean: Mean piston speed
Where:
1) C2 changes depending if at closed-valves (C2cv) or during gas-exchange (C2ge)
2) C3 changes depending if during compression (C3comp) or during combustion/expansion (C3comb)
3) Reference conditions (0) are at IVC or startTime if it is in closed-valve region.
4) C2corr changes depending if at closed-valves (C2corrcv) or during gas-exchange (C2corrge)
Args:
engine (EngineModel): The engine model from which taking data.
CA (float | Iterable | None, optional): Time for which computing heat transfer. If None, uses engine.time.time. Defaults to None.
"""
#Check arguments:
self.checkType(CA, (float, Iterable), "CA")
self.checkType(engine, EngineModel.EngineModel, "engine")
CA = engine.time.time if CA is None else CA
p = engine.data.p(CA)
V = engine.geometry.V(CA)
from libICEpost.src.engineModel.functions import upMean
UPistMean = upMean(n=engine.time.n, S=engine.geometry.S)
#Using bool operations to extend to vectorization
C3 = self.coeffs["C3comb"]*engine.time.isCombustion(CA) + self.coeffs["C3comp"]*(1. - engine.time.isCombustion(CA))
C2 = self.coeffs["C2cv"]*engine.time.isClosedValves(CA) + self.coeffs["C2ge"]*(1. - engine.time.isClosedValves(CA))
if self.coeffs["useTurbulence"]:
uPrime = engine.data.uPrime(CA)
C2corr = self.coeffs["C2corrcv"]*engine.time.isClosedValves(CA) + self.coeffs["C2corrge"]*(1. - engine.time.isClosedValves(CA))
C2 += C2corr*uPrime/UPistMean
refCA = engine.time.startTime if engine.time.isClosedValves(engine.time.startTime) else engine.time.IVC
refP = engine.data.p(refCA)
refT = engine.data.T(refCA)
refV = engine.geometry.V(refCA)
p_mot = self.p_mot(p0=refP, V=V, V0=refV)
Vs = engine.geometry.Vs
uwos = C2 * UPistMean + C3 * Vs * (p - p_mot) * refT / (refP * refV)
return uwos
#########################################################################
#Compute ptr:
[docs]
def p_mot(self, *, p0:float|Iterable, V:float|Iterable, V0:float|Iterable):
"""
p_mot = p0 * ( V0 / V )**nwos
"""
#Checking arguments:
self.checkType(p0, (float, Iterable), "p")
self.checkType(V, (float, Iterable), "V")
self.checkType(V0, (float, Iterable), "V0")
ptr = p0*(V0/V)**self.coeffs["nwos"]
return ptr
#########################################################################
#Add to selection table of Base
HeatTransferModel.addToRuntimeSelectionTable(Woschni)