This code determines the reactor volume and operating temperature that minimize the total cost of achieving a target conversion in a continuous stirred-tank reactor (CSTR). The reaction follows first-order kinetics with an Arrhenius-type rate constant (k₀ = 1.2×10⁸ min⁻¹, activation energy Ea = 60,000 J/mol), and the goal is to process a feed flow rate of 5.0 L/min to a desired conversion of 95%. The cost function combines a capital cost proportional to reactor volume ($15/L) with a heating cost that penalizes deviations from ambient temperature (298 K), creating a genuine trade-off: smaller reactors need higher temperatures to hit the conversion target, but higher temperatures cost more to maintain.
​
The first solution method uses Mathematica’s built-in NMinimize function to solve the constrained optimization problem directly, subject to the CSTR design equation (which links volume, temperature, and conversion through the rate constant) and a temperature bound of 300–500 K. This approach converges to an optimal volume of 29.4982 L and an optimal temperature of 413.957 K, yielding a minimum cost of $1518.16 — serving as a benchmark solution against which pso method can be checked.
​
The second approach implements Particle Swarm Optimization (PSO), a population-based metaheuristic that mimics social behavior in swarms of bees. Rather than solving the constraint analytically, the design equation is folded into the fitness function as a penalty term (weighted by 10⁶) that punishes solutions violating the volume-temperature relationship. The psoOptimize function is built with standard PSO mechanics: particles with positions and velocities, personal-best and global-best tracking, inertia weight decay from 0.9 to 0.4 over iterations, and velocity clamping to prevent divergent search behavior.
​
Running the PSO optimizer with 30 particles over 8000 iterations shows the swarm’s loss steadily declining from over 1600 down to a plateau around 1518.2, closely tracking the NMinimize benchmark. The convergence log printed every 500 iterations reveals rapid early improvement followed by fine-tuning, with the loss essentially flatlining after iteration 3500 — a typical PSO convergence characteristic.
​
Finally, the notebook compares both methods directly: PSO’s global best position lands at volume ≈ 29.3997 L and temperature ≈ 414.039 K with a cost of $1518.2, remarkably close to NMinimize’s exact optimum of $1518.16.
​
A log-scale convergence plot visualizes the swarm’s cost trajectory, confirming that this heuristic, derivative-free approach can reliably reproduce the results of a dedicated numerical optimizer — a useful validation for applying PSO to problems where analytical or gradient-based methods will be difficult or impossible to implement.
ClearAll["Global`*"]
volumetric flow rate in L/min
q=5.0;
Desired conversion
X=0.95;
$/L coefficient for Reactor cost
CR=15;
$/K^2 Heating cost coefficient
CH=0.08;
Arrhenius Equation
k0=1.2*10^8;(*1/min*)​​Ea=60000;(*J/mol*)​​R=8.314;(*J/mol.K*)​​k[T_]:=k0Exp[-Ea/(RT)];
Design equation for CSTR

Method based on NMinimize

Objective Function
Cost[V_,T_]:=CRV+CH(T-298)^2;
Optimization
solution=NMinimize[{Cost[V,T],V==qX/(k[T](1-X)),300<=T<=500,V>=0},{V,T},AccuracyGoal->20,PrecisionGoal->20,Method->"DifferentialEvolution"]
Vopt=V/.Last[solution];​​Topt=T/.Last[solution];​​Costopt=First[solution];​​​​Print["Optimal Volume = ",Vopt," L"];​​Print["Optimal Temperature = ",Topt," K"];​​Print["Minimum Cost = $",Costopt];
Out[]=
{1518.2,{V29.3979,T414.04}}
Optimal Volume = 29.3979 L
Optimal Temperature = 414.04 K
Minimum Cost = $1518.2
PSO approach
In[]:=
Fitness[{V_,T_}]:=Cost[V,T]+10^6(V-qX/(k[T](1-X)))^2
SwarmDim=2;(*2Dproblem*)
Upper and lower bounds for the search domain
FitnessLB={0,300};​​FitnessUB={100,600};
PSO parameters
c1=1.42;c2=1.42;w=0.72984;
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[Mod[j,500]==0,Print["PSO Iter ",j," Loss = ",gbestScore]];,{j,nIter}];​​{gbest,gbestScore,convergence}];
PSO run
result=psoOptimize[Fitness,SwarmDim,FitnessLB,FitnessUB,100,8000];​​{gbest,gbestScore,convergence}=result;
PSO Iter 500 Loss = 1607.34
PSO Iter 1000 Loss = 1570.74
PSO Iter 1500 Loss = 1567.48
PSO Iter 2000 Loss = 1520.66
PSO Iter 2500 Loss = 1519.01
PSO Iter 3000 Loss = 1518.47
PSO Iter 3500 Loss = 1518.3
PSO Iter 4000 Loss = 1518.2
PSO Iter 4500 Loss = 1518.2
PSO Iter 5000 Loss = 1518.2
PSO Iter 5500 Loss = 1518.2
PSO Iter 6000 Loss = 1518.2
PSO Iter 6500 Loss = 1518.2
PSO Iter 7000 Loss = 1518.2
PSO Iter 7500 Loss = 1518.2
PSO Iter 8000 Loss = 1518.2

PSO result vs . NMinimize solution

In[]:=
gbest
Out[]=
{29.3997,414.039}
In[]:=
gbestScore
Out[]=
1518.2
In[]:=
Print["Optimal Volume = ",Vopt," L"];​​Print["Optimal Temperature = ",Topt," K"];​​Print["Minimum Cost = $",Costopt];
Optimal Volume = 29.3979 L
Optimal Temperature = 414.04 K
Minimum Cost = $1518.2
PSO convergence plot

CITE THIS NOTEBOOK

Optimal design of a CSTR reactor: balancing capital and energy costs via global optimization​
by Housam Binous​
Wolfram Community, STAFF PICKS, July 4, 2026
https://community.wolfram.com/groups/-/m/t/3744889