Source code for PDSim.recip.core
from __future__ import division, print_function, absolute_import
from math import pi
from PDSim.misc.scipylike import trapz
from PDSim.flow import flow_models
from PDSim.core.core import PDSimCore
from ._recip import _Recip
[docs]
class Recip(PDSimCore,_Recip):
"""
Recip is derived from :class:`PDSimCore <PDSim.core.core.PDSimCore>`.
functions V_dV and heat_transfer_callback are provided in _Recip Cython class
"""
def __init__(self):
PDSimCore.__init__(self)
def __getstate__(self):
"""
A function for preparing class instance for pickling
Combine the dictionaries from the _Recip base class and the Recip
class when pickling
"""
py_dict = self.__dict__.copy()
py_dict.update(_Recip.__cdict__(self))
return py_dict
def __setstate__(self, d):
"""
A function for unpacking class instance for unpickling
"""
for k,v in d.iteritems():
setattr(self,k,v)
[docs]
def V_dV(self, theta):
"A thin wrapper around Cython code for pickling purposes"
return _Recip.V_dV(self, theta)
[docs]
def Vdisp(self):
r"""
Returns displacement of compressor in m\ :math:`^3`\ /revolution
"""
return 2*self.crank_length*self.A_piston
[docs]
def V_shell(self, theta):
return self.shell_volume, 0
[docs]
def TubeCode(self,Tube,**kwargs):
Tube.Q = flow_models.IsothermalWallTube(Tube.mdot,Tube.State1,Tube.State2,Tube.fixed,Tube.L,Tube.ID,T_wall=self.Tlumps[0])
[docs]
def Inlet(self, FlowPath, **kwargs):
try:
FlowPath.A=0.01**2/4*pi
mdot=flow_models.IsentropicNozzle(FlowPath.A,FlowPath.State_up,FlowPath.State_down)
return mdot
except ZeroDivisionError:
return 0.0
[docs]
def PistonLeakage(self, FlowPath, **kwargs):
try:
FlowPath.A=self.delta_gap*self.piston_diameter*pi
mdot=flow_models.IsentropicNozzle(FlowPath.A,FlowPath.State_up,FlowPath.State_down)
return mdot
except ZeroDivisionError:
return 0.0
[docs]
def Suction(self,FlowPath,**kwargs):
if FlowPath.key_up=='A':
## pressure in compressor higher than the inlet line
## valve is closed - no flow
return 0.0
else:
try:
FlowPath.A=self.suction_valve.A()
#FlowPath.A=self.A_suction
mdot=flow_models.IsentropicNozzle(FlowPath.A,FlowPath.State_up,FlowPath.State_down)
return mdot
except ZeroDivisionError:
return 0.0
[docs]
def Discharge(self,FlowPath,**kwargs):
if FlowPath.key_down=='A':
## pressure in compressor lower than the discharge line
## valve is closed - no flow
return 0.0
else:
try:
FlowPath.A=self.discharge_valve.A()
# FlowPath.A=self.A_discharge
mdot=flow_models.IsentropicNozzle(FlowPath.A,FlowPath.State_up,FlowPath.State_down)
return mdot
except ZeroDivisionError:
return 0.0
[docs]
def heat_transfer_callback(self,theta):
"A thin wrapper of the Cython code for pickling purposes"
return _Recip.heat_transfer_callback(self,theta)
# def heat_transfer_callback(self,theta):
# T_w = self.Tlumps[0] #[K]
# V,dV=self.V_dV(theta) #[m3,m3/radian]
# D_h = self.piston_diameter #[m]
# A_ht = pi*self.piston_diameter*(V/self.A_piston) #[m2]
#
# Pr = self.CVs['A'].State.Prandtl #[-]
# rho = self.CVs['A'].State.rho #[kg/m3]
# k = self.CVs['A'].State.k #[kW/m-K]
# mu = self.CVs['A'].State.visc #[Pa-s]
# T = self.CVs['A'].State.T #[K]
# u = abs(0.5*dV*self.omega/self.A_piston) #[m/s]
# Re = (rho*u*D_h)/mu #[kg/m3*m/s*m/Pa/s]=[-]
#
# h_c = 0.053*(k/D_h)*Pr**(0.6)*Re**(0.8) #[kW/m2/K]
# Q = h_c*A_ht*(T_w-T) #Net heat into control volume [kW]
# if self.CVs.N > 1:
# return listm([Q,0])
# else:
# return listm([Q])
[docs]
def mechanical_losses(self):
"""
Mathematical Analysis:
.. math::
x = {L_c}\\cos \\theta + \\sqrt {L_1^2 - L_c^2{{\\left( {\\sin \\theta } \\right)}^2}}
.. math::
\\dot x = - {L_c}\\sin \\theta \\dot \\theta + \\frac{{ - L_c^2\\sin 2\\theta }}{{2\\sqrt {L_1^2 - L_c^2{{\\left( {\\sin \\theta } \\right)}^2}} }}\\dot \\theta
.. math::
\\bar \\dot x = - \\frac{{\\dot \\theta }}{\\pi }\\int_0^\\pi {\\left[ { - {L_c}\\sin \\theta + \\frac{{ - L_c^2\\sin 2\\theta }}{{2\\sqrt {L_1^2 - L_c^2{{\\left( {\\sin \\theta } \\right)}^2}} }}} \\right]d\\theta }
.. math::
\\bar \\dot x = - \\frac{{\\dot \\theta }}{\\pi }\\left[ {{L_c}\\cos \\theta } \\right]_0^\\pi = - \\frac{{{L_c}\\dot \\theta }}{\\pi }( - 1 - 1) = \\frac{{2{L_c}\\dot \\theta }}{\\pi }
"""
#Oil with viscosity of 10 cSt (=10e-6 m^2/s) and density of 860 kg/m^3
A_length = pi*(self.piston_diameter)*self.piston_length #[m2]
u_ave = 2*self.crank_length/pi*self.omega
F_viscous = (self.mu_oil*A_length*u_ave)/self.delta_gap #[N]
W_dot_friction = (F_viscous*u_ave)/1000 #[kNm/s]=[kW]
return W_dot_friction
[docs]
def ambient_heat_transfer(self):
"""
The ambient heat transfer for the compressor in kW
Returns a positive value if heat is added to the compressor
"""
return self.h_shell*self.A_shell*(self.Tamb-self.Tlumps[0]) #[kW]
[docs]
def lump_energy_balance_callback(self):
#Mean heat transfer rate from gas to lump using trapezoidal method for numerical integration
#Note: Qdot_from_gas has opposite sign of heat transfer TO the gas as calculated in the heat_transfer_callback
#Note: Qdot_from_gas will likely be less than 0 because heat is being removed and delivered to the gas
self.Qdot_from_gas = -trapz(self.Q[0,0:self.Itheta],self.t[0:self.Itheta])/(self.t[self.Itheta-1]-self.t[0]) #[kW]
#Mechanical losses are added to the lump
self.Wdot_mechanical = self.mechanical_losses() #[kW]
#Heat transfer between the shell and the ambient
self.Qamb = self.ambient_heat_transfer() #[kW]
#Note: heat transfer TO the gas in the tubes is given a positive sign
# so sign is flipped for the lump
self.Qtubes = -sum([Tube.Q for Tube in self.Tubes])
return self.Qdot_from_gas + self.Wdot_mechanical + self.Qamb + self.Qtubes
[docs]
def pre_solve(self):
"""
Other calculations that are an indirect result of the inputs
"""
self.A_piston = pi*(self.piston_diameter)**2/4
self.V_dead=self.A_piston*self.x_TDC
self.A_discharge=pi*self.d_discharge**2/4
self.A_suction=pi*self.d_suction**2/4
#Name gets mangled in the core base class, so un-mangle it
def _PDSimCore__post_solve(self):
"""
{\\eta _{motor}} = \frac{{{{\\dot W}_{shaft}}}}{{{{\\dot W}_{shaft}} + {{\\dot W}_{motor}}}}
{\\eta _{motor}}\\left( {{{\\dot W}_{shaft}} + {{\\dot W}_{motor}}} \right) = {{\\dot W}_{shaft}}
{{\\dot W}_{motor}} = \frac{{{{\\dot W}_{shaft}}}}{{{\\eta _{motor}}}} - {{\\dot W}_{shaft}}
"""
#Call the base class function
PDSimCore._PDSimCore__post_solve(self)
#Extra code for the recip
#Motor losses
self.Wdot_motor = self.Wdot*(1/self.eta_motor-1)
#Electrical Power
self.Wdot_electrical = self.Wdot + self.Wdot_motor
#Overall isentropic efficiency
self.eta_oi = self.Wdot_i/self.Wdot_electrical
if __name__=='__main__':
print("Running this file doesn't do anything")