├── R.gif ├── nm.gif ├── q.gif ├── xd.gif ├── .gitattributes ├── McCabeThielePlot.png ├── README.md └── McCabeThiele.py /R.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trsav/mccabe-thiele/HEAD/R.gif -------------------------------------------------------------------------------- /nm.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trsav/mccabe-thiele/HEAD/nm.gif -------------------------------------------------------------------------------- /q.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trsav/mccabe-thiele/HEAD/q.gif -------------------------------------------------------------------------------- /xd.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trsav/mccabe-thiele/HEAD/xd.gif -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /McCabeThielePlot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trsav/mccabe-thiele/HEAD/McCabeThielePlot.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # McCabe-Thiele Method with Murphree Efficiency 3 | 4 | 5 | ## McCabe-Thiele Method 6 | The method was first published by Warren L. McCabe and Ernest Thiele in 1925, and is a graphical procedure of determining the number of trays within a distillation collumn. The Murphree tray efficiency modifies the equilibrium curve of the two components in order to better account for non-idealities. 7 | 8 | ### Current implimentation 9 | The current implementation presented here allows for a Murphree efficiency to be applied to the classical McCabe-Thiele plot. Whilst it is relatively easy online to find McCabe-Thiele 'calculators', there are few that have implementations accounting for the Murphree plate efficiency. 10 | 11 | ### Limitations 12 | * The molar heats of vaporization of the feed components are equal 13 | * For every mole of liquid vaporized, a mole of vapor is condensed 14 | * Heat effects such as heats of solution are negligible 15 | 16 | ## Effect of parameters 17 | 18 | 19 | Here shown on the left is the effect of changing the feed condition q, and on the right is shown the effect of changing the reflux ratio R. 20 | 21 | 22 | 23 | Here shown on the left is the effect of changing the desired distillate composition xd, and on the right is shown the effect of changing the Murphree efficiency. 24 | 25 | ## Function Use 26 | ``` 27 | DESCRIPTION: 28 | Performs the McCabe-Thiele construction in order to calculate 29 | optimum number of stages, and optimum feed stage. Also taking into 30 | account the Murphree Efficiency of the system. 31 | 32 | INPUTS: 33 | PaVap :Vapour pressure of component a (more volatile) 34 | PbVap :Vapour pressure of component b (less volatile) 35 | R_factor :Amount Rmin is scaled by to obtain the actual reflux ratio 36 | xf :Feed composition 37 | xd :Distillate composition 38 | xb :Bottoms composition 39 | q :Liquid fraction of feed 40 | nm :Murphree Efficiency 41 | 42 | OUTPUTS: 43 | A McCabe-Thiele plot, displaying optimum number of equilibrium stages, 44 | optimum feed stage, actual reflux ratio, actual bottoms composition. 45 | ``` 46 | ## Example 47 | Runnning the following: 48 | ``` 49 | PaVap=179.2 # Vapour pressure of a 50 | PbVap=74.3 # Vapour pressure of b 51 | xd=0.975 # Distillate composition 52 | xb=0.025 # Bottoms composition 53 | xf=0.5 # Feed composition 54 | q=0.5 # q (liquid fraction of feed) 55 | R_factor=1.8 # Reflux ratio = R_min* R_factor 56 | nm=0.75 #Murphree tray efficiency 57 | 58 | McCabeThiele(PaVap,PbVap,R_factor,xf,xd,xb,q,nm) 59 | ``` 60 | Produces the following output: 61 | 62 | 63 | 64 | **Please note: I wouldn't reccomend actually using this code to design a real distillation collumn, you should probably get an expert.** 65 | 66 | ## Author 67 | 68 | * **Tom Savage** - *Initial work* - [TomRSavage](https://github.com/TomRSavage) 69 | -------------------------------------------------------------------------------- /McCabeThiele.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import matplotlib.pyplot as plt 3 | 4 | 5 | def eq_og(xa,relative_volatility): 6 | ''' 7 | DESCRIPTION 8 | Returns equilibrium data from an input 9 | of liquid composition (xa) and relative volatility 10 | 11 | INPUTS: 12 | xa : Liquid Composition 13 | relative_volatility : Relative Volatility 14 | 15 | OUTPUTS: 16 | ya : Vapour Composition 17 | ''' 18 | ya=(relative_volatility*xa)/(1+(relative_volatility-1)*xa) 19 | # ya found using Dalton and Raoults laws 20 | return ya 21 | 22 | def eq(xa,relative_volatility,nm): 23 | ''' 24 | DESCRIPTION 25 | Returns equilibrium data from an input 26 | of liquid composition (xa) and relative volatility 27 | accounting for the Murphree Efficiency of the 28 | system 29 | 30 | INPUTS: 31 | xa : Liquid Composition 32 | relative_volatility : Relative Volatility 33 | nm : Murphree Efficiency 34 | 35 | OUTPUTS: 36 | ya : Vapour Composition 37 | ''' 38 | ya=(relative_volatility*xa)/(1+(relative_volatility-1)*xa) 39 | # ya found using Dalton and Raoults laws 40 | ya=((ya-xa)*nm)+xa # using definition of murphree efficiency 41 | return ya 42 | 43 | def eq2(ya,relative_volatility,nm): 44 | ''' 45 | DESCRIPTION 46 | Returns equilibrium data from an input 47 | of liquid composition (ya) and relative volatility 48 | accounting for the Murphree Efficiency of the 49 | system. This function is the inverse of eq(...) above. 50 | 51 | INPUTS: 52 | ya : Vapour Composition 53 | relative_volatility : Relative Volatility 54 | nm : Murphree Efficiency 55 | 56 | OUTPUTS: 57 | xa : Liquid Composition 58 | ''' 59 | # inverse of eq() takes the form of a quadratic 60 | a=((relative_volatility*nm)-nm-relative_volatility+1) 61 | b=((ya*relative_volatility)-ya+nm-1-(relative_volatility*nm)) 62 | c=ya 63 | xa=(-b-np.sqrt((b**2)-(4*a*c)))/(2*a) # solving quadratic using 64 | # quadratic formula 65 | return xa 66 | 67 | def stepping_ESOL(x1,y1,relative_volatility,R,xd): 68 | ''' 69 | DESCRIPTION: 70 | Performs a single step over the ESOL 71 | operating line. 72 | 73 | INPUTS: 74 | x1 : Initial liquid composition on ESOL 75 | y1 : Initial vapour composition on ESOL 76 | relative_volatility : Relative Volatility 77 | R : Reflux Ratio 78 | xd : Distillate Composition 79 | 80 | OUTPUTS: 81 | x1 : Initial liquid composition 82 | x2 : Liquid composition after stepping 83 | y1 : Initial vapour composition 84 | y2 : Vapour composition after stepping 85 | 86 | ''' 87 | x2=eq2(y1,relative_volatility,nm) #getting new liquid comp 88 | y2=(((R*x2)/(R+1))+(xd/(R+1))) #ESOL equation 89 | return x1,x2,y1,y2 90 | 91 | def stepping_SSOL(x1,y1,relative_volatility,\ 92 | ESOL_q_x,ESOL_q_y,xb): 93 | ''' 94 | DESCRIPTION: 95 | Performs a single step over the SSOL 96 | operating line. 97 | 98 | INPUTS: 99 | x1 : Initial liquid composition on ESOL 100 | y1 : Initial vapour composition on ESOL 101 | relative_volatility : Relative Volatility 102 | ESOL_q_x : Point at which ESOL intersects q-line (x) 103 | ESOL_q_y : Point at which ESOL intersects q-line (y) 104 | xb : Bottoms composition 105 | 106 | OUTPUTS: 107 | x1 : Initial liquid composition 108 | x2 : Liquid composition after stepping 109 | y1 : Initial vapour composition 110 | y2 : Vapour composition after stepping 111 | 112 | ''' 113 | x2=eq2(y1,relative_volatility,nm) # getting new liquid comp 114 | m=((xb-ESOL_q_y)/(xb-ESOL_q_x)) # gradient of SSOL 115 | c=ESOL_q_y-(m*ESOL_q_x) # intercept of SSOL 116 | y2=(m*x2)+c # SSOL equation in form 'y=mx+c' 117 | return x1,x2,y1,y2 118 | 119 | def McCabeThiele(PaVap,PbVap,R_factor,xf,xd,xb,q,nm): 120 | ''' 121 | DESCRIPTION: 122 | Performs the McCabe-Thiele construction in order to calculate 123 | optimum number of stages, and optimum feed stage. Also taking into 124 | account the Murphree Efficiency of the system. 125 | 126 | INPUTS: 127 | PaVap :Vapour pressure of component a (more volatile) 128 | PbVap :Vapour pressure of component b (less volatile) 129 | R_factor :Amount Rmin is scaled by to obtain the actual reflux ratio 130 | xf :Feed composition 131 | xd :Distillate composition 132 | xb :Bottoms composition 133 | q :Liquid fraction of feed 134 | nm :Murphree Efficiency 135 | 136 | OUTPUTS: 137 | A McCabe-Thiele plot, displaying optimum number of equilibrium stages, 138 | optimum feed stage, actual reflux ratio, actual bottoms composition. 139 | ''' 140 | # Ensuring errors don't occur regarding dividing by 0 141 | if q==1: 142 | q-=0.00000001 143 | if q==0: 144 | q+=0.00000001 145 | 146 | relative_volatility=PaVap/PbVap #obtaining relative volatility from definition 147 | xa=np.linspace(0,1,100) #creating x-axis 148 | ya_og=eq_og(xa[:],relative_volatility) #getting original equilibrium data 149 | ya_eq=eq(xa[:],relative_volatility,nm) #getting modified equilibrium data 150 | # taking into account the Murphree Efficiency 151 | 152 | x_line=xa[:] #creating data-points for y=x line 153 | y_line=xa[:] 154 | 155 | # finding where the q-line intersects the equilibrium curve 156 | # takes the form of a quadratic equation 157 | al=relative_volatility 158 | a=((al*q)/(q-1))-al+(al*nm)-(q/(q-1))+1-nm 159 | b=(q/(q-1))-1+nm+((al*xf)/(1-q))-(xf/(1-q))-(al*nm) 160 | c=xf/(1-q) 161 | 162 | if q>1: 163 | q_eqX=(-b+np.sqrt((b**2)-(4*a*c)))/(2*a) 164 | else: 165 | q_eqX=(-b-np.sqrt((b**2)-(4*a*c)))/(2*a) 166 | # where the q-line intersects the equilibrium curve (x-axis) 167 | q_eqy=eq(q_eqX,relative_volatility,nm) 168 | # where the q-line intersects the equilibrium curve (y-axis) 169 | 170 | theta_min=xd*(1-((xd-q_eqy)/(xd-q_eqX))) # ESOL y-intercept to obtain Rmin 171 | R_min=(xd/theta_min)-1 # finding Rmin 172 | R=R_factor*R_min # multiplying by R_factor to obtain R 173 | theta=(xd/(R+1)) # finding new ESOL y-intercept 174 | 175 | ESOL_q_x=((theta-(xf/(1-q)))/((q/(q-1))-((xd-theta)/xd))) 176 | # Where the new ESOL intercepts the q-line (x-axis) 177 | ESOL_q_y=(ESOL_q_x*((xd-theta)/xd))+theta 178 | # Where the new ESOL intercepts the q-line (y-axis) 179 | 180 | 181 | plt.figure() # The following code plots the Mccabe Thiele diagram 182 | plt.axis([0,1,0,1]) #creating axes between 0-1 183 | plt.plot([xd,xd],[0,xd],color='k',linestyle='--') # distillate comp line 184 | plt.plot([xb,xb],[0,xb],color='k',linestyle='--') # bottoms comp line 185 | plt.plot([xf,xf],[0,xf],color='k',linestyle='--') # feed comp line 186 | 187 | #plt.plot([xd,0],[xd,theta_min],color='r',linestyle='--') # ESOL at Rmin 188 | '''UN-COMMENT TO SEE ESOL FOR Rmin ^^^''' 189 | 190 | plt.plot([xd,ESOL_q_x],[xd,ESOL_q_y],color='k') # ESOL at R 191 | plt.plot([xb,ESOL_q_x],[xb,ESOL_q_y],color='k') # SSOL 192 | 193 | x1,x2,y1,y2=stepping_ESOL(xd,xd,relative_volatility,R,xd) 194 | step_count=1 # current number of equilibrium stages 195 | plt.plot([x1,x2],[y1,y1],color='k') # Step_1 196 | plt.plot([x2,x2],[y1,y2],color='k') # Step_2 197 | plt.text(x2-0.045,y1+0.045,step_count) 198 | while x2>ESOL_q_x: # up until the q-line, step down 199 | x1,x2,y1,y2=stepping_ESOL(x2,y2,relative_volatility,R,xd) 200 | plt.plot([x1,x2],[y1,y1],color='k') 201 | plt.plot([x2,x2],[y1,y2],color='k') 202 | step_count+=1 # incrementing equilibrium stage count 203 | plt.text(x2-0.045,y1+0.045,step_count) # label the stage 204 | 205 | feed_stage=step_count # obtaining optimum feed stage 206 | 207 | x1,x2,y1,y2=stepping_SSOL(x1,y1,relative_volatility\ 208 | ,ESOL_q_x,ESOL_q_y,xb) 209 | plt.plot([x1,x2],[y1,y1],color='k') 210 | plt.plot([x2,x2],[y1,y2],color='k') 211 | step_count+=1 212 | while x2>xb: # while the composition is greater than desired 213 | x1,x2,y1,y2=stepping_SSOL(x2,y2,relative_volatility\ 214 | ,ESOL_q_x,ESOL_q_y,xb) 215 | # continue stepping... 216 | plt.plot([x1,x2],[y1,y1],color='k') 217 | plt.plot([x2,x2],[y1,y2],color='k') 218 | plt.text(x2-0.045,y1+0.045,step_count) # label stage 219 | step_count+=1 #increment equilibrium stage counter 220 | plt.plot([x2,x2],[y1,0],color='k') 221 | xb_actual=x2 222 | stages=step_count-1 223 | plt.plot(x_line,y_line,color='k') # x=y line 224 | plt.plot(xa,ya_og,color='k') # equilibrium curve 225 | plt.plot(xa,ya_eq,color='g',linestyle='--') # equilibrium curve (with efficiency) 226 | plt.plot([xf,ESOL_q_x],[xf,ESOL_q_y],color='k') #q- line 227 | 228 | #plt.plot([ESOL_q_x,q_eqX],[ESOL_q_y,q_eqy],color='r',linestyle='--') #q- line 229 | '''UN-COMMENT TO SEE FULL q LINE ^^^''' 230 | 231 | plt.xlabel('xa') #Just a few labels and information... 232 | plt.ylabel('ya') 233 | plt.text(0.6,0.5,'Rmin= '+str(round(R_min,3))) 234 | plt.text(0.6,0.45,'R= '+str(round(R,3))) 235 | plt.text(0.6,0.4,'xb actual= '+str(round(xb_actual,3))) 236 | plt.text(0.6,0.35,'Stages= '+str(stages)) 237 | plt.text(0.6,0.3,'Feed Stage= '+str(feed_stage)) 238 | plt.title('xd='+str(xd)+'\n'+\ 239 | 'xb='+str(xb)+\ 240 | ' xd='+str(xd)+'\n'+\ 241 | 'zf='+str(xf)+\ 242 | ' q='+str(round(q,3))+'\n'+\ 243 | 'R='+str(R_factor)+'*Rmin'+\ 244 | ' Murphree Efficiency='+str(nm)) 245 | plt.grid(True) # wack the grid on for bonus points 246 | plt.show() 247 | return 248 | 249 | 250 | '''PARAMETERS''' 251 | 252 | PaVap=179.2 # Vapour pressure of a 253 | PbVap=74.3 # Vapour pressure of b 254 | xd=0.975 # Distillate composition 255 | xb=0.025 # Bottoms composition 256 | xf=0.5 # Feed composition 257 | q=0.5 # q 258 | R_factor=1.3 # Reflux ratio = R_min* R_factor 259 | nm=0.75 #Murphree Efficiency 260 | 261 | 262 | McCabeThiele(PaVap,PbVap,R_factor,xf,xd,xb,q,nm) 263 | --------------------------------------------------------------------------------