You are on page 1of 8

Contents

1 Explore techela a bit

2 The Basics - isothermal reactor design with single reactions


2.1 Chemical reactions . . . . . . . . . . . . . . . . . . . . . . . .
2.2 Reaction extent . . . . . . . . . . . . . . . . . . . . . . . . . .

1
1
5

3 Recommended exercises
org-toggle-latex-overlays org-toggle-pretty-entities

Explore techela a bit

Look at the techela menu tq-index generates an index buffer with clickable
links
tq-search search the course notes for a word
tq-send-error-report send me an email about an error with techela
tq-email send me an email about anything else
Each of those commands can be run from those links, from the menu, or
by typing M-x command name.

The Basics - isothermal reactor design with single reactions

2.1

Chemical reactions

Chemical reaction transform reactants to products.


Consider a reaction aA + bB + qQ + sS +
symbols on the left are reactants
symbols on the right are products
The lower case letters are stoichiometric coefficients
Stoichiometric coefficients relate the amounts of each reactant
that react to the amounts of products produced
The upper case letters are symbols for reactant and product species
For specificity let us consider
1

aA + bB cC + dD
We will express this reaction as:
0 = 3 A3 + 4 A4 1 A1 2 A2
where we have substituted A = A1 and a = 1 , C = A3 and c = 3 ,
etc. . .
In the most compact form we might write this as a sum over all N
species for a reaction:
PN 1

i Ai = 0
where i is the stoichiometric coefficient (negative for reactants, positive
for products), or more preferrably in matrix equation form:
~=0

~ A
~ is the vector
where
~ is the vector of stoichiometric coefficients, and A
of chemical species.
i=0

It is conventional that the stoichiometric coefficients of reactants are


negative and for products the stoichiometric coefficients are positive.
Atoms cannot be destroyed in non-nuclear chemical reactions, hence
it follows that the same number of atoms entering a reactor must
also leave the reactor. The atoms may leave the reactor in a different
molecular configuration due to the reaction, but the total mass leaving
the reactor must be the same.
We consider the water gas shift reaction:
CO + H2 O
H2 + CO2 .
The total mass at any time will be MCO + MH2 O + MH2 + MCO2 .
These are related to the number of moles of each species through
the species molecular weights.
~ be a vector that is the number of moles of each species. Then,
Let N
~ M~W .
the total mass is: N
Stoichiometry constrains the relationship between the moles of each
species during reaction.
Suppose we start with this initial number of moles of each species:
[N0 , N0 , 0, 0].
2

Now, if n moles of A_1 reacts, we know that n moles of A_2


react, and n moles of A_3 and A_4 are produced.
~0 +
In otherwords, the new number of moles of each species is: N
~
~
n~
. And the new mass is correspondingly: (N0 + n~
) M W or:
M0 + n~
M~W .
In a properly balanced chemical reaction, there are the same number of
each type of atom on each side of the reaction, so the sum of molecular
weights of reactants must be the same as products, and
~ M~W = 0.
Therefore, the total mass does not change for any n!
We can illustrate the conservation of mass with the following equation:

~ M~W = 0. Where
~ is the stoichiometric coefficient vector and M~W
is a column vector of molecular weights.
For simplicity, we use pure isotope molecular weights, and not the
isotope-weighted molecular weights. This equation simply examines
the mass on the right side of the equation and the mass on left side of
the equation.
< HEAD numpy.array used for all kinds of arrays numpy.dot used
for dot product
Whats the use of "range"?
1

x= range(5)

2
3

print(list(x))

4
5
6
7
8

=======
pydoc:numpy.array
pydoc:numpy.dot
pydoc:range

9
10
11
12

#+BEGIN_SRC python :results output org drawer


print(list(range(4)))
>>>>>>> 7e83c7c6b508670886df612746eb313fd64c536d

===== [0, 1, 2, 3] > 7e83c7c6b508670886df612746eb313fd64c536d


1
2

import numpy as np
import pycse.orgmode as org

3
4
5
6

# stoichiometric vector for


# CO + H2O -> H2 + CO2
alpha = np.array([-1, -1, 1, 1])

7
8

MW = np.array([28, 18, 2, 44])

# Molecular weights gm/mol

9
10

print('1. ', np.dot(alpha, MW))

11
12

print('2. ', np.sum([a * m for a, m in zip(alpha, MW)]))

13
14
15
16
17
18
19

# Here is some old-fashioned code to do the same thing. do not do


# this. even though it works:
total = 0
for i in [0, 1, 2, 3]:
total = total + alpha[i] * MW[i]
print('3. ', total)

20
21
22
23
24

# Kudos if you thought of this:


import operator
print('4. ', sum(map(operator.mul, alpha, MW)))
# This is called functional programming

25
26
27

# This is the new syntax in Python 3 for matrix multiplication


print('5. ', alpha @ MW)

28
29
30
31

# Note * is an element-wise multiplication for arrays. Arrays are not the same as lists.
print('6. ', sum(alpha * MW))
print(alpha * MW) # in matlab this is alpha .* MW

1. 0
2. 0
3. 0
4. 0
5. 0
6. 0
[-28 -18
1
2

44]

import numpy as np
a = np.array([1, 2, 3])

3
4

print(2 * a)

5
6
7

print(np.dot([1, 1, 1], [2, 2, 2]))

[2 4 6] 6
Stoichiometry also determines if the total number of moles in a reaction
change. Even though the total mass is constant, the total number of moles
may change. Here are three examples showing how this is possible.
1. CO + H2 O H_2 + CO_2 (no total mole change)
4

2. H2 O H_2 + 1/2 O_2 (Total moles increase by 0.5 mol per mol
water reacted)
3. N_2 + 3H_2 2 NH_3 (Total moles decrease by two moles for every
mole of N_2 reacted)
The change in number of moles is given by =
1
2
3
4
5

PN

i=0 i .

import numpy as np
# Water-gas shift
alpha = np.array([-1, -1, 1, 1]);

# stoichiometric vector for CO +


# H2O -> H2 + CO2
print('Change in moles for the WGS = {0} moles'.format(sum(alpha)))

6
7
8

alpha = np.array([-1, 1, 0.5]) # H2O -> H2 + 1/2 O2


print('Change in moles for water splitting = {0} moles'.format(sum(alpha)))

9
10
11

alpha = np.array([-1, -3, 2]) # N2 + 3H2 -> 2 NH3


print('Change in moles for the ammonia synthesis = {} moles'.format(sum(alpha)))

Change in moles for the WGS = 0 moles


Change in moles for water splitting = 0.5 moles
Change in moles for the ammonia synthesis = -2 moles
Changing the total number of moles in a reaction will have a big effect
in gas phase reactions because it results in changing volumetric flow rates.
We will come back to this later.

2.2

Reaction extent

We now consider formalizing the change in moles of each species when


reactions occur. Consider:
2H2 + O2 2H2 O
which we write as:
0 = 2A3 2A1 A2
If we start with NA1 ,0 moles at some time, and later have NA1 moles
later, then stoichiometry dictates that:
NA1 NA1 ,0
2

NA2 NA2 ,0
1

NA3 NA3 ,0
2

=X

We call X the extent of reaction, and it has units of moles. We can


show generally that:
5

NJ = NJ,0 + J X
or for a flow system:
FJ = FJ,0 + J X
X has units of mol/time for dimensional consistency in a flow system
Note that the extent of reaction as written is extensive, and depends
on how the reaction is written through the stoichiometric coefficients.
It does not, however, depend on a particular species.
If we have a constant volume reactor and a constant volumetric flow,
we can use an intensive reaction extent:
CJ = CJ,0 + J .
is now an intensive reaction extent X/V , with units of mol / vol.
or 0 is now an intensive reaction extent X/, with units of mol / vol /
time.
Note that there are limits on the maximum value of because we
cannot have negative concentrations. If we set CJ to zero, we derive
max =

CJ,0
J

If there are multiple reactants present, then you must pick the smallest
positive (non-zero) max to avoid getting negative concentrations of
one species.
Consider this reaction:
H2 + 0.5O2 H2 O
If you start with 0.55 mole of $H2 , and 0.2 mol of O2 . What is max ?
1

import numpy as np

2
3
4

M0 = np.array([0.55, 0.2])
alpha = np.array([-1.0, -0.5])

5
6
7
8
9
10
11
12
13

<<<<<<< HEAD
species = ['Hydrogen', 'Oxygen']

#zip. How to use?--->


for sp, x in zip(species, -M0 / alpha):
#zip extracts element
print('{0:>10s} {1:1.2f}'.format(sp,x)) # 10s is 10 character
# 10>s makes it right
=======
species = ['H2', 'O2']

14

importnat !!
wise in a array
wide string
f: float 1.2 is..2 decimal places i
aligned. To make it center we use: 10^s

15
16
17
18

for sp, x in zip(species, -M0 / alpha):


#
print('{0:4s}{1:1.2f}'.format(sp, x))
print('{0} {1}'.format(sp, x))
>>>>>>> 7e83c7c6b508670886df612746eb313fd64c536d

19
20

print('The maximum extent is {0} moles.'.format(min(- M0 / alpha)))

< HEAD
Hydrogen 0.55
Oxygen 0.40
=====
H2
O2

0.55
0.4

> 7e83c7c6b508670886df612746eb313fd64c536d
The maximum extent is 0.4 moles.
Now for that extent, what is the reaction compostion? Let us work it
out. zip
1

import numpy as np

2
3
4

M0 = np.array([0.55, 0.2, 0.0])


alpha = np.array([-1.0, -0.5, 1.0])

5
6

xi = 0.4

7
8
9

M = M0 + alpha * xi
species = ['H2', 'O2', 'H2O']

10
11
12

for s,m in zip(species, M):


print('{0:5s} {1:1.2f} moles'.format(s,m))

H2
O2
H2O

0.15 moles
0.00 moles
0.40 moles

You can see that at that extent we have consumed all of the oxygen.
We would call that the limiting reagent, because the reaction cannot
proceed further since one of the reactants is gone.
Rather than work in terms of reaction extents, you may choose to
define a fractional extent:
7

org-toggle-latex-overlays
= max /
which leads upon substitution to:
CJ = CJ,0 (1 )
This new quantity is sometimes referred to as conversion. Conversion has the nice property of being dimensionless, and bounded
between 0 and 1.

Recommended exercises

Repeat ?? in fractional extent and conversion.


1

import numpy as np

2
3
4

M0= np.array([0.55, 0.2])


alpha=np.array([-1, -0.5])

5
6

species = ['H2', 'O2', 'H2O']

7
8

x= -M0/alpha

9
10

xmax= min(x)

11
12

theta= xmax/x

13
14

M=M0*(1-theta)

15
16
17

for s,m in zip(species, M):


print('{0:5s} {1:1.2f} moles'.format(s,m))

H2 0.15 moles O2 0.00 moles


1

import numpy as np

2
3
4
5
6

a= np.array([6,8,9])
b= np.array([2,4,3])
c= a/b
d=min(c)

7
8

print (d)

2.0

You might also like