├── 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 |
--------------------------------------------------------------------------------