This notebook finds the optimal interstage pressures (P2–P5) for a 5-stage compressor operating between P1 = 1 bar and Pn = 8 bar, where the gas suction temperature rises monotonically across stages (300 → 305 → 313 → 325 → 345 K) due to imperfect (unequal) intercooling, using an ideal-gas polytropic work model (γ = 1.4, R = 0.287 kJ/kg·K for Air).
Two objective functions are compared:
1. Pure work minimization (WtotalSymbolic) — solved via PSO and cross-checked with NMinimize (Differential Evolution), gives a minimum work ≈ 199.0 kJ/kg at pressures {1.84, 3.20, 5.09, 7.08} bar. Because cooling is unequal, the optimal pressure ratios are not equal across stages — instead, the optimality condition requires
T
in,i
×
γ-1
γ
r
i
to be constant (≈357.2) across all stages, so stages with higher suction temperature compensate with a lower pressure ratio.
2. Work + cost objective (loss) — adds a simple economy-of-scale cost penalty (costCoeff · Σ
0.6
r
i
) to the thermodynamic work, solved via the same custom PSO routine. This pulls the optimum toward pressures {1.69, 2.77, 4.31, 6.24} bar (total objective ≈ 520.8), with a more front-loaded pressure-ratio distribution ({1.69, 1.64, 1.56, 1.45, 1.28}) compared to the work-only case, since the sub-linear cost term discourages concentrating a large pressure ratio in any single stage.
The notebook includes the PSO optimizer (inertia-weight annealing, velocity clamping, boundary clipping), a log-scale convergence plot (loss gap vs. iteration), and a verification step confirming the
T
in,i
×
γ-1
γ
r
i
= const relationship does not hold anymore when we add the capital cost contribution to the total thermodynamic work.
Number of stages
n=5;
Suction pressure, e.g.bar
P1=1.0;
Final discharge pressure, e.g.bar
Pn=8.0;
Ratio of specific heats, cp/cv
gamma=1.4;
Specific gas constant, kJ/(kg K)
R=0.287;
In[]:=
T1=300.0;​​dT={5.0,8.0,12.0,20};​​Tin=Prepend[T1+Accumulate[dT],T1];​​​​Print["Stage suction temperatures (K): ",Tin];
Stage suction temperatures (K): {300.,305.,313.,325.,345.}

PSO Solution

General symbolic formula
WtotalSymbolic[{P2_,P3_,P4_,P5_}]:=Module[{r},r={P2/P1,P3/P2,P4/P3,P5/P4,Pn/P5};Sum[(gamma/(gamma-1))*R*Tin[[i]]*((r[[i]])^((gamma-1)/(gamma))-1),{i,1,5}]]
Clip each COLUMN of a matrix against its own scalar bound
clipMatrix[mat_,lbv_,ubv_]:=Transpose[MapThread[Clip[#1,{#2,#3}]&,{Transpose[mat],lbv,ubv}]];​​​​clampMatrix[mat_,vmaxv_]:=Transpose[MapThread[Clip[#1,{-#2,#2}]&,{Transpose[mat],vmaxv}]];
PSO Optimizer
psoOptimize[lossFunc_,dim_,lb_,ub_,nParticles_:30,nIter_:100,wMax_:0.9,wMin_:0.4,c1_:1.42,c2_:1.42,vClampFrac_:0.2]:=Module[{particles,velocities,pbest,pbestScore,gbest,gbestScore,convergence={},r1,r2,scores,gbestIdx,vmax,wIter},vmax=vClampFrac*(ub-lb);​​particles=Transpose@Table[RandomReal[{lb[[i]],ub[[i]]},nParticles],{i,dim}];​​velocities=ConstantArray[0.,{nParticles,dim}];​​pbest=particles;​​pbestScore=lossFunc/@particles;​​gbestIdx=First@Ordering[pbestScore,1];​​gbestScore=pbestScore[[gbestIdx]];​​gbest=pbest[[gbestIdx]];​​Do[wIter=wMax-(wMax-wMin)*(j-1)/(nIter-1);​​r1=RandomReal[1,{nParticles,dim}];​​r2=RandomReal[1,{nParticles,dim}];​​velocities=wIter*velocities+c1*r1*(pbest-particles)+c2*r2*(ConstantArray[gbest,nParticles]-particles);​​velocities=clampMatrix[velocities,vmax];​​particles+=velocities;​​particles=clipMatrix[particles,lb,ub];​​scores=lossFunc/@particles;​​pbest=MapThread[If[#3<#2,#1,#4]&,{particles,pbestScore,scores,pbest}];​​pbestScore=MapThread[Min,{pbestScore,scores}];​​gbestIdx=First@Ordering[pbestScore,1];​​If[pbestScore[[gbestIdx]]<gbestScore,gbestScore=pbestScore[[gbestIdx]];​​gbest=pbest[[gbestIdx]];];​​AppendTo[convergence,gbestScore];​​If[j<10||Mod[j,10]==0,Print["PSO Iter ",j," Loss = ",gbestScore]];,{j,nIter}];​​{gbest,gbestScore,convergence}];
In[]:=
dim=4;
In[]:=
UB=10{1,1,1,1};​​LB=1{1,1,1,1};
Simple cost term: cost per stage∝(pressure ratio)^0.6
Cost weighting per stage-tune as needed
costCoeff=50;
Economy-of-scale exponent
costExp=0.6;
loss[{P2_,P3_,P4_,P5_}]:=Module[{r,work,cost},r={P2/P1,P3/P2,P4/P3,P5/P4,Pn/P5};​​(*thermodynamicwork,sameasbefore*)work=Sum[(gamma/(gamma-1))*R*Tin[[i]]*(r[[i]]^((gamma-1)/gamma)-1),{i,1,n}];​​(*costpenalty:sumof(ratio)^0.6acrossstages*)cost=costCoeff*Sum[r[[i]]^costExp,{i,1,n}];​​work+cost];
Run PSO on the combined work+cost objective
{gbestCost,gbestScoreCost,convergenceCost}=psoOptimize[loss,4,LB,UB,30,150];
PSO Iter 1 Loss = 542.541
PSO Iter 2 Loss = 535.371
PSO Iter 3 Loss = 531.029
PSO Iter 4 Loss = 529.15
PSO Iter 5 Loss = 528.708
PSO Iter 6 Loss = 528.012
PSO Iter 7 Loss = 528.012
PSO Iter 8 Loss = 527.648
PSO Iter 9 Loss = 526.37
PSO Iter 10 Loss = 523.079
PSO Iter 20 Loss = 520.945
PSO Iter 30 Loss = 520.917
PSO Iter 40 Loss = 520.853
PSO Iter 50 Loss = 520.844
PSO Iter 60 Loss = 520.843
PSO Iter 70 Loss = 520.842
PSO Iter 80 Loss = 520.842
PSO Iter 90 Loss = 520.842
PSO Iter 100 Loss = 520.842
PSO Iter 110 Loss = 520.842
PSO Iter 120 Loss = 520.842
PSO Iter 130 Loss = 520.842
PSO Iter 140 Loss = 520.842
PSO Iter 150 Loss = 520.842
In[]:=
Pstages=Prepend[Append[gbestCost,Pn],P1]
Out[]=
{1.,1.68967,2.76714,4.31198,6.24069,8.}
In[]:=
ratios=Table[Pstages[[i+1]]/Pstages[[i]],{i,1,n}]
Out[]=
{1.68967,1.63769,1.55828,1.44729,1.28191}
In[]:=
Print["Minimum work + cost objective: ",gbestScoreCost];​​Print["Optimal interstage pressures (bar): ",Pstages];​​Print["Stage pressure ratios: ",ratios];
Minimum work + cost objective: 520.842
Optimal interstage pressures (bar): {1.,1.68967,2.76714,4.31198,6.24069,8.}
Stage pressure ratios: {1.68967,1.63769,1.55828,1.44729,1.28191}
Gap to the best-known solution at each iteration
gap=convergenceCost-gbestScoreCost;
Convergence plot
ListLogPlotgap,

Out[]=

CITE THIS NOTEBOOK

Optimization of a 5-stage air compressor: unequal interstage cooling + economy-of-scale cost penalty​
by Housam Binous​
Wolfram Community, STAFF PICKS, July 4, 2026
https://community.wolfram.com/groups/-/m/t/3744734