Performance Functions#

These functions are available in the ccp.point module and they are mainly used by the ccp.Point class in the performance calculation.

ccp.point.disch_from_suc_disch_T_head(suc, disch_T, head, polytropic_method=None)#

Calculate discharge state from suction, discharge temperature and head.

Pressure is the iteration variable at the fixed discharge temperature: the polytropic head increases monotonically with pressure, from about zero at the suction pressure to the enthalpy rise at the isentropic pressure, so the root is bracketed by those two states.

Parameters:
succcp.State

Suction state.

disch_Tpint.Quantity, float

Discharge temperature (degK).

headpint.Quantity, float

Polytropic head (J/kg).

Returns:
dischccp.State

Discharge state.

ccp.point.disch_from_suc_disch_p_eff(suc, disch_p, eff, polytropic_method=None)#

Calculate discharge state from suction, discharge pressure and efficiency.

Temperature is the iteration variable at the fixed discharge pressure: the polytropic efficiency is 1 at the isentropic temperature and decreases monotonically above it, so the root is bracketed from the isentropic state upwards. The initial guess scales the real isentropic head with the ideal-gas ratio of polytropic to isentropic head.

Parameters:
succcp.State

Suction state.

disch_ppint.Quantity, float

Discharge pressure (Pa).

effpint.Quantity, float

Polytropic efficiency (dimensionless).

Returns:
dischccp.State

Discharge state.

ccp.point.disch_from_suc_head_eff(suc, head, eff, polytropic_method=None)#

Calculate discharge state from suction, head and efficiency.

The discharge enthalpy is fixed by h_d = h_s + head / eff; pressure is the iteration variable along that isenthalp. The polytropic head is zero at the suction pressure and equals h_d - h_s at the isentropic pressure, and increases monotonically in between, so the root is bracketed by those two states. The initial guess is the ideal-gas polytropic pressure for the suction isentropic exponent.

Parameters:
succcp.State

Suction state.

headpint.Quantity, float

Polytropic head (J/kg).

effpint.Quantity, float

Polytropic efficiency (dimensionless).

Returns:
dischccp.State

Discharge state.

ccp.point.disch_from_suc_volume_ratio_eff(suc, volume_ratio, eff, polytropic_method=None)#

Calculate discharge state from suction, volume ratio and efficiency.

Parameters:
succcp.State

Suction state.

volume_ratiopint.Quantity, float

Ratio between suction and discharge specific volumes (v_s / v_d).

effpint.Quantity, float

Polytropic efficiency (dimensionless).

Returns:
dischccp.State

Discharge state.

ccp.point.eff_isentropic(suc, disch)#

Isentropic efficiency.

Parameters:
succcp.State

Suction state.

dischccp.State

Discharge state.

Returns:
eff_isentropicpint.Quantity

Isentropic efficiency.

ccp.point.eff_pol(suc, disch)#

Polytropic efficiency.

Parameters:
succcp.State

Suction state.

dischccp.State

Discharge state.

Returns:
eff_polpint.Quantity

Polytropic efficiency (dimensionless).

ccp.point.eff_pol_huntington(suc, disch, disch_s=None)#

Polytropic efficiency calculated by the 3 point method described by [Huntington, 1985].

Parameters:
succcp.State

Suction state.

dischccp.State

Discharge state.

Returns:
eff_pol_huntingtonpint.Quantity

Polytropic efficiency as described by [Huntington, 1985] (dimensionless).

ccp.point.eff_pol_mallen_saville(suc, disch, disch_s=None)#

Polytropic efficiency as per [Mallen and Saville, 1977].

Parameters:
succcp.State

Suction state.

dischccp.State

Discharge state.

Returns:
eff_pol_mallen_savillepint.Quantity

Mallen-Saville polytropic efficiency (dimensionless).

ccp.point.eff_pol_sandberg_colby(suc, disch, disch_s=None)#

Sandberg-Colby polytropic efficiency.

Parameters:
succcp.State

Suction state.

dischccp.State

Discharge state.

Returns:
eff_pol_sandberg_colby: pint.Quantity

Sandberg-Colby polytropic efficiency (dimensionless).

ccp.point.eff_pol_sandberg_colby_multistep(suc, disch, disch_s=None)#

Sandberg-Colby multistep polytropic efficiency.

Parameters:
succcp.State

Suction state.

dischccp.State

Discharge state.

disch_sccp.State, optional

Accepted for interface compatibility with the other polytropic methods (it is the scratch state passed by the point solver) and not used by this method.

Returns:
eff_pol_sandberg_colby_multistep: pint.Quantity

Sandberg-Colby multistep polytropic efficiency (dimensionless).

ccp.point.eff_pol_schultz(suc, disch, disch_s=None)#

Polytropic efficiency as per [Schultz, 1962].

Parameters:
succcp.State

Suction state.

dischccp.State

Discharge state.

disch_sccp.State, optional

Reusable state object to avoid copying. If provided, this state will be passed to head_pol_schultz for reuse.

Returns:
eff_pol_schultzpint.Quantity

Schultz polytropic efficiency (dimensionless).

ccp.point.f_sandberg_colby(suc, disch)#

Correction factor as proposed by [Sandberg and Colby, 2013].

\[\begin{equation} f_p = \frac{(h_d - h_s) - T_{avg} (s_d - s_s)} {(\frac{n}{n-1})(p_d v_d - p_s v_s)} \end{equation}\]
Parameters:
succcp.State

Suction state.

dischccp.State

Discharge state.

Returns:
f_sandberg_colbypint.Quantity

Polytropic head correction factor as described by [Sandberg and Colby, 2013] (dimensionless).

ccp.point.f_schultz(suc, disch, disch_s=None)#

Correction factor as per [Schultz, 1962] eq 32:

\[\begin{equation} f = \frac{H_{ds} - H_s}{(\frac{n_s}{n_s - 1})(p_d v_{ds} - p_s v_s)} \end{equation}\]
Parameters:
succcp.State

Suction state.

dischccp.State

Discharge state.

disch_sccp.State, optional

Reusable state object to avoid copying. If provided, this state will be updated and used for calculations. If None, a copy of disch will be created.

Returns:
f_schultzfloat

Schultz polytropic factor.

ccp.point.flow_from_phi(D, phi, speed)#

Calculate flow from non dimensional phi.

Parameters:
Dfloat, pint.Quantity

Impeller outer diameter (m).

phipint.Quantity, float

Flow coefficient (m³/s).

speedpint.Quantity, float

Speed (rad/s).

Returns:
u_calcpint.Quantity, float

Impeller tip speed.

ccp.point.head_from_psi(D, psi, speed)#

Calculate head from non dimensional psi.

Parameters:
Dfloat, pint.Quantity

Impeller outer diameter (m).

psipint.Quantity, float

Head coefficient.

speedpint.Quantity, float

Speed (rad/s).

Returns:
u_calcpint.Quantity, float

Impeller tip speed.

ccp.point.head_isentropic(suc, disch, disch_s=None)#

Isentropic head.

Parameters:
succcp.State

Suction state.

dischccp.State

Discharge state.

disch_sccp.State, optional

Reusable state object to avoid copying. If provided, this state will be updated and used for calculations. If None, a copy of disch will be created.

Returns:
head_isentropicpint.Quantity

Isentropic head.

ccp.point.head_pol(suc, disch)#

Polytropic head.

The polytropic head is calculated as per [Schultz, 1962] eq. 27:

\[\begin{equation} H_p = (\frac{n}{n - 1}) (p_d v_d - p_s v_s) \end{equation}\]

And \(n\) is calculated by n_exp().

Parameters:
succcp.State

Suction state.

dischccp.State

Discharge state.

Returns:
head_polpint.Quantity

Polytropic head (J/kg).

ccp.point.head_pol_huntington(suc, disch, disch_s=None)#

Polytropic head calculated by the 3 point method described by [Huntington, 1985].

The polytropic head in this case is calculated from the polytropic efficiency with:

\[\begin{equation} \frac{1}{e} = 1 + \frac{\frac{(s_d - s_s)}{R}} {a \ln(\frac{p_d}{p_s}) + b((\frac{p_d}{p_s}) - 1) + \frac{c}{2}(\ln{(\frac{p_d}{p_s})})^2} \end{equation}\]

The constants \(a\), \(b\) and \(c\) are calculated with:

\[\begin{split}\begin{equation} a = z_s - b \\ b = \frac{(z_s + z_d - 2z_{int})}{((\frac{p_s}{p_s})^{0.5} - 1)^2} \\ c = \frac{(z_d - a - b(\frac{p_d}{p_s}))}{\ln{(\frac{p_d}{p_s})}} \end{equation}\end{split}\]

The intermediate values are calculated interactively:

\[\begin{split}\begin{equation} p_{int} = \sqrt{p_s p_d} \\ T_{int}' = T_{int} \exp{(\frac{(s_{int}' - s_{int})}{c_p})} \end{equation}\end{split}\]

And \(s_{int}\) is calculated by:

\[\begin{equation} s_{int}' = s_s + (s_d - s_s) \frac{\frac{a}{2}\ln{(\frac{p_d}{p_s})} + b((\frac{p_s}{p_s})^{0.5} - 1)) + \frac{c}{8}(\ln{(\frac{p_d}{p_s})})^2} {a\ln(\frac{p_d}{p_s}) + b((\frac{p_d}{p_s})-1) + \frac{c}{2}(\ln(\frac{p_d}{p_s}))^2} \end{equation}\]
Parameters:
succcp.State

Suction state.

dischccp.State

Discharge state.

Returns:
head_pol_huntingtonpint.Quantity

Polytropic head as described by [Huntington, 1985] (J/kg).

ccp.point.head_pol_mallen_saville(suc, disch, disch_s=None)#

Polytropic head as per [Mallen and Saville, 1977] calculated with:

\[\begin{equation} H_p = (h_d - h_s) - (s_d - s_s) \frac{T_d - Ts}{\ln{(\frac{T_d}{T_s})}} \end{equation}\]
Parameters:
succcp.State

Suction state.

dischccp.State

Discharge state.

Returns:
head_pol_mallen_savillepint.Quantity

Mallen-Saville polytropic polytropic head (J/kg).

ccp.point.head_pol_sandberg_colby(suc, disch, disch_s=None)#

Polytropic head method as described in section 5-2.2 of [ASME, 2022].

\[\begin{equation} w_{p} = (h_{d} - h_{i}) - (\frac{T_{i} + T_{d}}{2}) (s_{d} - s_{i}) \end{equation}\]
Parameters:
succcp.State

Suction state.

dischccp.State

Discharge state.

Returns:
head_pol_sandberg_colbypint.Quantity

Polytropic head as described in [ASME, 2022] (J/kg).

ccp.point.head_pol_sandberg_colby_multistep(suc, disch, disch_s=None, nstep=10)#

Polytropic head multistep method as described in section 5-2.4 [ASME, 2022].

This implements the numerical integration method from ASME PTC 10-2022 Figure 5-2.4-1 flowchart: the compression is split into nstep steps of equal pressure ratio, each step is a single-step Sandberg-Colby compression with the same polytropic efficiency, and that efficiency is the one for which the path ends at the measured discharge temperature. The number of steps is then increased by 5 until the efficiency changes by less than 1e-5 (relative).

The efficiency is found by a bracketed secant (ccp.roots.solve_monotone()) starting from the single-step Sandberg-Colby estimate; the path temperature decreases monotonically with the step efficiency.

Parameters:
succcp.State

Suction state.

dischccp.State

Discharge state.

disch_sccp.State, optional

Scratch state (the one passed by the point solver); a copy of disch is used when it is not given.

nstepint, optional

Initial number of integration steps. Default is 10.

Returns:
head_pol_sandberg_colby_multisteppint.Quantity

Polytropic head as described by [ASME, 2022] (J/kg).

ccp.point.head_pol_schultz(suc, disch, disch_s=None)#

Polytropic head corrected by the [Schultz, 1962] factor.

\[\begin{equation} H_{p_{schultz}} = f_{schultz} H_p \end{equation}\]

Where \(f_{schultz}\) is calculated by f_schultz() and \(H_p\) is calculated by head_pol().

Parameters:
succcp.State

Suction state.

dischccp.State

Discharge state.

disch_sccp.State, optional

Reusable state object to avoid copying. If provided, this state will be passed to f_schultz for reuse.

Returns:
head_pol_schultzpint.Quantity

Schultz polytropic head (J/kg).

ccp.point.head_reference(suc, disch, num_steps=100)#

Reference head.

The reference head consists of the integration of \(v dp\) along the polytropic path as described by [Huntington, 1985] and [Sandberg and Colby, 2013]. To achieve this we break the polytropic path into a series of subpaths. The compression ratio \(R_{c_i}\) for each segment, as described by [Sandberg and Colby, 2013] is calculated with:

\[\begin{equation} R_{c_i} = \sqrt[n_{steps}]{\frac{p_d}{p_s}} \end{equation}\]

The calculation consists of two loops. One converges the \(T_1\) temperature at each step by evaluating the difference between \(H = v_{avg} \Delta_p\) and \(H = e \Delta_h\). The other evaluates the efficiency by checking the difference between the last \(T_1\) to the discharge temperature \(T_d\).

Parameters:
succcp.State

Suction state.

dischccp.State

Discharge state.

Returns:
head_referencepint.Quantity

Reference head as described by [Huntington, 1985]. (J/kg).

eff_referencefloat

Reference efficiency as described by [Huntington, 1985] (dimensionless).

ccp.point.head_reference_2017(suc, disch, num_steps=100)#

Reference head.

The reference head consists of the integration along the polytropic path as described by [Huntington, 2017]. Contrary to the method presented by [Huntington, 1985], this method does not use a specific volume linearized over each step of the integration, instead, it is based on the assumption that the compressibility factor varies linearly with the pressure within each step.

In this case the inner loop of the method is calculated by:

\[\begin{split} \begin{equation} a = \frac{z_i (\frac{p_{i+1}}{p_i}) - z_{i+1}} {(\frac{p_{i+1}}{p_i} - 1)} \\ b = \frac{z_{i+1} - z_i} {(\frac{p_{i+1}}{p_i} - 1)} \\ (s_{i+1} - s_i) = R \frac{(1-e)}{e}( a \ln{(\frac{p_{i+1}}{p_i})} + b(\frac{p_{i+1}}{p_i} - 1)) \end{equation}\end{split}\]
Parameters:
succcp.State

Suction state.

dischccp.State

Discharge state.

Returns:
head_referencepint.Quantity

Reference head as described by [Huntington, 2017]. (J/kg).

eff_referencefloat

Reference efficiency as described by [Huntington, 2017] (dimensionless).

ccp.point.isentropic_disch_from_rho(suc, disch_rho)#

Discharge state of an isentropic compression to a target density.

The state is found on the suction isentrope with (rho, T) inputs (see _isentropic_T_at_rho()) rather than with a (rho, s) flash: for dense fluids that flash has two roots, the physical compression and a cold root below the suction pressure, and which one it returns depends on the backend’s internal state.

Parameters:
succcp.State

Suction state.

disch_rhopint.Quantity

Target discharge density.

Returns:
dischccp.State

Discharge state of the isentropic compression to disch_rho.

ccp.point.mach(suc, speed, D)#

Calculate the Mach number.

Parameters:
succcp.State

Suction state.

speedpint.Quantity, float

Impeller speed (rad/s).

Dfloat, pint.Quantity

Impeller outer diameter (m).

Returns:
machpint.Quantity

Mach number (dimensionless).

ccp.point.n_exp(suc, disch)#

Polytropic exponent.

The polytropic exponent \(n\) is calculated as per [Schultz, 1962] eq. 27:

\[\begin{equation} n = \frac{\log{\frac{p_d}{p_s}}}{\log{\frac{v_s}{v_d}}} \end{equation}\]
Parameters:
succcp.State

Suction state.

dischccp.State

Discharge state.

Returns:
n_expfloat

Polytropic exponent.

ccp.point.phi(flow_v, speed, D)#

Flow coefficient.

Parameters:
flow_vfloat, pint.Quantity

Impeller flow (m³/s).

speedfloat, pint.Quantity

Impeller speed (rad/s).

Dfloat, pint.Quantity

Impeller outer diameter (m).

Returns:
phipint.Quantity

Flow coefficient (dimensionless).

ccp.point.power_calc(flow_m, head, eff)#

Calculate power.

Parameters:
flow_mpint.Quantity, float

Mass flow (kg/s).

headpint.Quantity, float

Head (J/kg).

effpint.Quantity, float

Efficiency (dimensionless).

Returns:
powerpint.Quantity

Power (watt).

ccp.point.reynolds(suc, speed, b, D)#

Calculate the Reynolds number.

Parameters:
succcp.State

Suction state.

speedpint.Quantity, float

Impeller speed (rad/s).

bfloat, pint.Quantity

Impeller width at the outer blade diameter (m).

Dfloat, pint.Quantity

Impeller outer diameter (m).

Returns:
reynoldspint.Quantity

Reynolds number (dimensionless).

ccp.point.speed_from_psi(D, head, psi)#

Calculate speed from non dimensional psi.

Parameters:
Dfloat, pint.Quantity

Impeller outer diameter (m).

headpint.Quantity, float

Polytropic head.

psipint.Quantity, float

Head coefficient.

Returns:
u_calcpint.Quantity, float

Impeller tip speed.

ccp.point.u_calc(D, speed)#

Calculate the impeller tip speed.

Parameters:
Dfloat, pint.Quantity

Impeller outer diameter (m).

speedpint.Quantity, float

Impeller speed (rad/s).

Returns:
u_calcpint.Quantity

Impeller tip speed (m/s).

Solvers#

The discharge closures above reduce to one monotone equation in a pressure or a temperature, bracketed by the suction and the isentropic discharge, and are solved with:

Scalar root finding for monotone residuals with a physical bracket.

The discharge closures of ccp.Point all reduce to one equation in one variable (a pressure or a temperature) whose residual is monotone between two physically meaningful states, the suction and the isentropic discharge. The solver here exploits that: it starts from a guess, brackets the root while it iterates, never leaves the physical interval and never re-evaluates a state it already knows. Flash calculations dominate the cost of a closure, so the number of residual evaluations is what matters.

ccp.roots.solve_monotone(f, x0, lo, hi, rtol=1e-08, increasing=True, x1=None, max_evals=100, name='residual', f0=None, f1=None)#

Root of a monotone residual f on [lo, hi], starting from x0.

Parameters:
fcallable

Residual f(x); monotone on [lo, hi]. It may raise ValueError or ZeroDivisionError for a value of x it cannot evaluate (a flash that does not converge, a degenerate state); the step is then shortened towards the last good point.

x0float

Initial guess.

lo, hifloat

Physical interval that contains the root. The ends are only evaluated when the iteration is clamped to them.

rtolfloat, optional

Relative tolerance on x: the iteration stops when the bracket width or the last step is below rtol * |x|. Default 1e-8.

increasingbool, optional

True when f increases with x (default), False when it decreases.

x1float, optional

Second guess; when given, the first step is the secant through x0 and x1 instead of a geometric step from x0.

max_evalsint, optional

Maximum number of residual evaluations. Default 100.

namestr, optional

Label used in error messages.

f0, f1float, optional

Residuals already known at x0 and x1; they are used instead of evaluating f there.

Returns:
xfloat

The root.

Raises:
ValueError

When the residual has the same sign at lo and hi (no root in the interval), when f cannot be evaluated around the iterate, or when max_evals is exceeded.

Similarity#

ccp.similarity.check_similarity(point_sp, point_t)#

Function to check similarity between two different points.

Parameters:
point_spccp.Point

The specified (reference) point in the compressor map.

point_tccp.Point

The new point in the compressor map.

Returns:
similarity_resultsstr

Report with the flow coefficient, volume ratio, Mach and Reynolds similarity values and their PTC 10 limits (the Reynolds limits are the PTC 10-2022 envelope of reynolds_limits(), as ratios to the specified Reynolds number).

ccp.similarity.reynolds_limits(remsp)#

Reynolds number envelope of ASME PTC 10-2022 (Fig. 3-3.5-1).

Parameters:
remspfloat

Machine Reynolds number of the specified point.

Returns:
lower, upperfloat

Limits on the test machine Reynolds number. Raises ValueError below the 9e4 lower bound of the figure.

[ASM22] (1,2,3,4)

ASME. Axial and Centrifugal Compressors. American Society of Mechanical Engineers, New York, NY, USA, 2022.

[Hun85] (1,2,3,4,5,6,7,8)

R. A. Huntington. Evaluation of Polytropic Calculation Methods for Turbomachinery Performance. Journal of Engineering for Gas Turbines and Power, 107(4):872–876, 10 1985. doi:10.1115/1.3239827.

[Hun17] (1,2,3)

Richard Huntington. Another new look at polytropic calculations methods for turbomachinery performance. pages, 09 2017. doi:10.13140/RG.2.2.10331.87841.

[MS77] (1,2)

M Mallen and G Saville. Polytropic processes in the performance prediction of centrifugal compressors. Institution of mechanical engineers, London, United Kingdom, pages 89–96, 1977.

[SC13] (1,2,3,4)

Mark E Sandberg and Gary M Colby. Limitations of asme ptc 10 in accurately evaluation centrifugal compressor thermodynamic performance. In Proceedings of the 42nd Turbomachinery Symposium. Texas A&M University. Turbomachinery Laboratories, 2013. doi:10.21423/R1505Q.

[Sch62] (1,2,3,4,5)

John M. Schultz. The Polytropic Analysis of Centrifugal Compressors. Journal of Engineering for Power, 84(1):69–82, 01 1962. doi:10.1115/1.3673381.