You are on page 1of 82

The IKP Matlab Companion

Matlab exercises in TKP4105, TKP4110,


TKP4120, TKP4140, TKP4160
and TMT4140

Tore Haug-Warberg
D  C E, NTNU
E-mail address: haugwarb@nt.ntnu.no
URL: http://www.nt.ntnu/˜haugwarb
The Author wants to thank Ph.D. student Bjørn Tore Løvfall for his help with HYSYS
and the diffusion problem, and Ph.D. student Antonio Carlos Brandao Araujo for his
help with the control theory example and ODE description. They have also been very
helpful with the Matlab documentation in general. He also wants to thank prof. Hallvard
Svendsen for his kind interest in this little project.
Contents

List of Tables v
Preface vii
Chapter 1. Getting started 1
Chapter 2. Basic concepts 3
1. Homogeneous containers (vectors and matrices) 3
2. Heterogeneous containers (lists) 6
3. User-defined data types (structs) 7
4. Input/output issues 8
5. Tricks of the trade 8
Chapter 3. How to solve equations 9
1. Linear equations 9
2. Independent reactions 12
3. Linear parameter estimation 12
4. Polynomials 14
5. Single non-linear equations 15
6. Sets of many non-linear equations 16
Chapter 4. Write your own functions 19
1. The function concept 19
2. Vector functions 19
3. Iterative functions (algorithms) 20
4. Recursion — good, evil or maybe bad? 20
Chapter 5. Functionals or function(function)s 23
1. Integration 23
2. Ordinary differential equations 23
3. Unconstrained optimization 25
4. Optimization with constraints 25
5. Process control 26
Chapter 6. String parsing 29
1. Chemical formula arithmetics 29
2. Cool stuff (regular expressions) 30
Appendix A. Language elements 33
Appendix B. Examples 37
Appendix C. Matlab code 39
1. randolph 39
2. octane 41
3. figure 2 8 42
iii
iv CONTENTS

4. partialinv 43
5. fertilizer balance 43
6. acid base reaction matrix 45
7. water viscosity 1bar fit 46
8. water vapor pressure fit 47
9. water density 1bar fit 49
10. acid base titration curve 50
11. colebrook 51
12. pressure drop at fixed flow 51
13. friction and reynold 52
14. flow at fixed pressure drop 52
15. laminar 53
16. colebrook vs laminar 53
17. chon 54
18. water viscosity 1bar 54
19. water vapor pressure 54
20. water density 1bar 54
21. rachford rice 55
22. diffusion 55
23. pitot tube 57
24. pitot integrand 58
25. mingibb 58
26. CSTR process control 59
27. CSTR time derivatives 61
28. ODE Jacobian 62
29. mw from formula parser 63
30. mw binop 63
31. make formula matrix 64
32. get formula vector 66
33. greenhouse gases from HYSYS 67
Appendix D. Ruby code 69
1. greenhouse gases from HYSYS 69
Appendix E. Data files 71
1. pages from water vapor pressure data 71
2. pages from water density 1bar data 72
3. water viscosity 1bar data 73
4. pages from HYSYS report 73
List of Tables

1.1 Programming abstractions 1

3.1 Nitro-phosphate fertilizer plant 11


4.1 Recursive calculation of Fibonacci-numbers 22
6.1 Operator table 29
6.2 The most common regular expressions 31

A.1 File functions 33


A.2 Special variables 33
A.3 Special characters 33
A.4 Basic commands 33
A.5 Program flow instructions 34
A.6 Instantiation operators 34
A.7 Plotting commands 34
A.8 Relational operators 34
A.9 Algebraic operators 35
A.10 Set functions 35
A.11 Transcendental functions 35
A.12 String functions 35
A.13 Linear algebra functions 36
A.14 Advanced linear algebra functions 36
A.15 Functionals 36

v
Preface

My arguments for enrolling at the Chemistry Faculty in the late 1970s were subtle:
I disliked mathematics and hated philosophy, but loved to experiment with (explosive)
chemicals. It was therefore quite natural for me to study in Trondheim — just modest
mathematics and no Exam Philosophicum. So, here I am, writing a philosophically in-
clined preface to a companion in mathematical programming! My naive view lasted for
only one year, however, or more precisely till my first course in physical chemistry and
thermodynamics. I then realized that the subject which had fascinated me as a young boy
could be represented by thermodynamic state functions, and after a freshman course in
FORTRAN programming I have since spent my professional life in the borderland be-
tween chemistry, mathematics and computer science. In retrospect this has not been such
a bad fate because the field has expanded tremendously, which means I have had plenty
of interesting things to do.
So what is studying, and why should we worry about programming? Basically, I
think we have three qualities which make us stand out from other mammals, including
our cousins — the big apes:
Mental abstraction
Verbal communication
Artistic inclination

To me it is important to master all three skill factors, at least to some degree. I


therefore enjoy to enjoy∗ mathematics (abstract thinking), computer programming (mind
extension) and carpentry (artistic pleasure). However, communication is maybe the most
important skill factor these days. But, talking about communication there are at least four
levels we need to worry about†:

Talking (99)
Reading (80)
Writing (25)
Programming (1)

The numbers indicate the percentage of the population that I expect master the sub-
ject to such a degree that it help them in communicating with other people. I have no
scientific background for my statements, and, before someone accuses me for having
fascistic motives, I want to say that it is not my intention (nor is it my profession) to cate-
gorize people according to their skills — I simply want you to realize that learning about
programming is likely to be a “painful” process in the beginning. However, the fraction
of students who enroll to the technical studies at NTNU makes up about two percent of
the juvenile vintage in Norway and provided it is true that our university recruits among

It is meant to be a recursive statement — think about it twice.

These subjects form, together with mathematics, the five basic skills that all children shall master
according to the 200X-reform of the Norwegian primary school system.
vii
viii PREFACE

the “science buffs”, it is likely that much more than one percent of you already have
some acquaintance with computers and computer programming. My hope is therefore
that many of you shall come to appreciate computer programming as a main productivity
tool. Second, it is also my hope that some of you will join my research group working on
computerized thermodynamics!
Before we get started I should mention that this little Matlab companion is intended
to follow the students at IKP over 2–3 years in several different subjects of engineering
disciplines:
TKP4105 Separation technology
TKP4110 Chemical reaction engineering
TKP4120 Process engineering
TKP4140 Process control
TKP4160 Transport phenomena
TMT4140 Applied thermodynamics

Since I lack a first hand experience with each of the course syllabuses it is difficult
for me to give a chronological overview of the exercises. A thematic presentation is then
more natural, especially when keeping maintainability in mind.
Even though this is a course in mathematical programming it will not give you any
formal training, neither in mathematics nor in programming. The focus is rather on prac-
tical problem solving. Now, since most of the code is vectorized it means that linear
algebra is a prerequistite for reading the companion. Having said this, I still want to
show that math is done simpler, safer and faster in a mathematical programming lan-
guage like Matlab, as compared to hand calculations, spread-sheet programming, or no
calculations at all∗. The exercises are taken from many different subjects, but I have put
quite a lot of effort in keeping the programming style both as general and as uniform as
possible (which is the main reason this is a one-man show — it is hard to synchronize
two programmers).
Throughout the course we shall make use of Matlab, but please understand me right
when I say that this is not a Matlab course. Matlab is excellent for prototyping issues, it
is abundant, and it has a gentle learning curve, but it is unfortunately a rather inconsis-
tent language. Without some critical sense you may therefore develop bad programming
habits, although less so than in e.g. Excel. This is not to say I want a crusade against
Matlab or Excel (well, perhaps), what I really want to tell is that the world is big and that
there are hundreds of programming languages out there — all having their strong and
weak points. The moral is: Pick the language that is best suited for your job! Take e.g.
PostScript. Few people realize that this is anything but a relict from Adobe which makes
artistic print-outs and fancy fonts available to the end user. However, PostScript is a pro-
gramming language in its own right and you can write a complete simulation code in this
language if you really want to†. I have therefore avoided Matlab-specific programming
the best I can, just to make sure you will be able to migrate to other (script) languages
like Python or Ruby without too much difficulty.


Plain belief or guts feeling are student favorites which seldom turn out to yield better results than
to-the-point calculations.

Wouldn’t it be an intellectual challenge to let the printer do the number-crunching while the computer
could concentrate on other things (the question is only what job that should be).
CHAPTER 1

Getting started

First of all I should let you know that the Matlab code which is included in Appendix
C can also be found on my home page http://www.nt.ntnu/˜haugwarb/matlabcourse. This
might save you same typing errors.
Before learning about programming (or any other scientific subject) you should def-
initely ask yourself what the subject is about. In computer terminology program means
one out of three things: A systematic plan for the automatic solution of a problem by a
computer, or the precise sequence of instructions enabling a computer to solve a problem,
or to prepare a program code (ref: Webster’s Encyclopedic Unabridged Dictionary). All
three meanings are adequate for the current purpose.
Most programming languages are built around the idea that you shall be able to de-
clare variables, write expressions of some kind, make assignments to the variables, and
transfer execution control to external procedures∗. External in this context means the pro-
cedure has its own namespace where the variables are given a local meaning. In other
words; to bring information from the outside world into the procedure it has to be copied,
and vice versa; everything you want to be visible outside has to be copied back. Some
languages got more abstraction mechanisms, some got less, but these four are the ones
needed in Matlab (see Table 1.1).

T 1.1: Programming abstractions. With this I mean the


different building blocks a language consists of.

Declaration function[lnp]=antoine(T,c) T and c hold copies of


the arguments used in
the call to antoine
Expression c(1)+c(2)/(T+c(3)) The expression is eval-
uated but not assigned
Assignment lnp=c(1)+c(2)/(T+c(3)) Variable lnp now holds
a copy of the evaluated
expression
Procedure antoine(x,y) x and y are copied into
antoine, the calculated
result is copied back

Matlab belongs to a family of languages called script languages (Python, Ruby, Perl,
etc.). This is contrary to languages which has to be compiled before you get an executable
code† (Pascal, C++, FORTRAN, etc.). The big challenge in this respect is programming

In Matlab, the function abstraction is mixed up with the declaration keyword function which is used
to define functions. For this reason I write procedure when I am referring to the abstraction, and function
when I refer to the declaration, see Table 1.1.

Nowadays often called an application. On the Windows platform this is a file having the file extension
.exe
1
2 1. GETTING STARTED

speed versus calculation efficiency and code syntax versus semantics∗. Script languages
are very suitable for rapid prototyping and testing, while a compiled code is more secure
in the sense that you can ask for full control over its execution.
In Appendix A you will find a small subset of commands, operators, etc. taken from
the standard Matlab implementation. The list is complete in the respect that nothing more
will be needed in this course. In Appendix B I have given a few examples on how the
Matlab-code looks.


Whereas correct syntax only tells us that the program can be executed, a correct semantics tells us
that the program does exactly what it is intended to do — now that is a real challenge!
CHAPTER 2

Basic concepts

The expression syntax∗ in Matlab is not very different from what you have been taught
in mathematics, e.g. a=2; b=3; c=(a-b)ˆ2; c==1;. The central issue here is the statement.
A statement is interpreted from the left and proceeds all the way to the first semicolon
or the end-of-line (there are four statements in the previous example). If the statement
contains an equal sign it is said to be an assignment (there are three assignments in the
previous example). At this point things start to diverge from what you have seen before.
To illustrate possible pit-falls let us rewrite the Matlab code into mathematical terms:
a =2
b =3
def
c = (a − b)2
?
c =1
First, I assign the values 2 and 3 to the variables a and b, then I define c to be the complete
square in a and b, and in the fourth line I ask myself whether c is equal to 1 or not. In
daily speech most people just continue to use the = operator and say “equal to” in all
four cases. Now, this is something a computer cannot understand without some help!
E.g. in Matlab, the first two lines are OK, but the third line gives trouble. Matlab does
not know about symbolic algebra (contrary to e.g. Maple, but that is another story). The
closest we come to a definition in Matlab is the function concept explained in Section 4.1.
Therefore, issuing the statement c=(a-b)ˆ2; in line three, Matlab will simply evaluate the
square using the current values of a and b. If a and b are not yet assigned you will get the
error message ??? Undefined function or variable ’a’.
The fourth line represents a boolean test (booleans are numbers that can take the val-
ues true or false†). In Matlab there are no booleans so this feature has to be sneaked in
using ordinary numbers combined with the convention that 1 is true, and 0 is false. To
test the equality we have to write c==1; which in this particular case will return 1 (true).
Hence, we can also write something like d=c==1; where the outcome from the test ex-
pression is assigned to the variable d. The moral is: Beware of the difference between
definitions, assignments and boolean tests! You must also understand that Matlab exe-
cutes one line at a time. Hence you must make sure that all statements (lines) comes in
the correct order.

1. Homogeneous containers (vectors and matrices)


The basic data type in Matlab is a matrix-like‡ container of numbers. The numbers
that Matlab operate on are so-called doubles. One double occupies 8 byte of information.

Rules for writing correct expressions, i.e. 2 + 3 ∗ 2 will be evaluated as 2 + (3 ∗ 2) and not (2 + 3) ∗ 2.

Don’t be too puzzled, this is not very different from an electric charge having the values plus or minus.

What exactly is a matrix? There are at least four meanings of the term: A point in vector space, a
linear operator, a row or column basis for a vector space, or just a data “container”. The last interpretation
fits the use of matrices in Matlab best.
3
4 2. BASIC CONCEPTS

There are 8 bit in one byte which means there are 63 bit available for storing numbers (the
last bit is the so-called sign-bit). In practise this means you can represent all integer values
in the range −253 , 253 exactly. Outside this region the number field gets more and more
scattered until you reach the limit ±21024 . Beyond this Matlab will use the notation inf
to signify that you are outside the number representation (over-flow).  Creeping towards
−1075 −1075 −1075
zero you can represent numbers down to ±2 . Inside the range 2 ,2 you will
always get the result 0, i.e. there is no under-flow in Matlab.
Let us go back to the container issue. In mathematical texts you will meet several
notations for vectors and matrices. The notation I tend to favor is this one:
 
1 2
A=
3 4
 
a= 5 6
a = 3.141592 . . .
N = 13,
where capital boldface denotes a matrix, lower boldface denotes a vector, and normal font
(either capital or lower case) is a scalar. In Matlab there are no bold fonts which means
vectors and scalars will look the same:
snippet from matlab matrix.m starts here
A = [1,2;3,4];
a = [5,6];
a = 3.141592;
N = 13;
matlab matrix.m ends here
Of importance for us is to realize that Matlab does not distinguish between matrices,
vectors and scalars. To Matlab everything is a matrix which means that executing the
size() command on A, a and N will tell they are all two-dimensional objects (do this).
We could therefore forget about most of what we have learned in mathematics and start
doing things entirely the Matlab-way. This is not encouraged, however, and I shall do my
best to present code that is “mathematically correct” in this course.
Assume we want to calculate and plot the ideal gas pressure as a function of volume
for a given temperature. Mathematically, the operations can be written∗
R = 8.31453 J mol-1 K-1
T = 273.15 K
N = 7 mol
 
v = 0.1 m3, 0.3 m3, . . . , 1.5 m3
e = (1, 1, . . . , 1)T
t = Te
p = NR diag (v)−1 t
Note the use of matrix/vector notation in the example. It certainly makes the code com-
pact, but you must know how to handle array and matrix products! Translated to Matlab
the same operations look like this:
snippet from ideal gas isotherm.m starts here

Since there are no standard mathematical notation available for plotting vectors I cannot show this
operation.
1. HOMOGENEOUS CONTAINERS (VECTORS AND MATRICES) 5

clear;

R = 8.31453;
T = 273.15;
N = 7;
v = [0.1:0.1:1.5];
e = ones(size(v))’;
t = T*e;
p = N*R*inv(diag(v))*t;

plot(v,p);
xlabel(’Volume [mˆ3]’);
ylabel(’Pressure [Pa]’);
title([’p(V)-plot at ’,num2str(T),’ K’]);
ideal gas isotherm.m ends here
There are a couple of things we should note here. First of all Matlab has a vector con-
structor [from:step:to] which is very handy. Second, the matrix constructor ones(size(v))
do two things at one time. Besides filling the vector e with 1’s, it also ensures that e
inherits the dimensions of v (or shape if you like). Now, this is a good programming
practise! The opposite is also valid: Never, never, . . ., never enter the same definition
twice in the code, and never let two dependent matrices (or two vectors) have indepen-
dent size definitions! Finally, I should mention that in practise I would consider to change
the last line in the calculation to p=N*R*(t./v). This is both a matter of CPU-time and
readability, although I shall not claim that the compact code is a better alternative under
all circumstances.

§ 1 Repeat the calculations in the last example for the isotherms T=[250:20:350].
Use v=logspace(0.1,10,100)’ to construct the pV-diagram. Make your best at cal-
culating everything as matrix products (no for-loops, index variables, etc.), and
make sure your results can be plotted using the command semilogx(v,P) where P
is a dim (v) × dim (T )-matrix. For your own understanding of the physical behavior
you should also try the command loglog(v,P).

I  . Nothing really new here, but to become fluent in array program-
ming you must exercise a lot. I want therefore to stress the importance of the compact
notation used in ideal gas isotherms. So, do not fake you have grasped the idea but make
sure you understand! 
snippet from ideal gas isotherms.m starts here
clear;

R = 8.31453;
t = [250:20:350];
N = 7;
v = logspace(-1,1,100)’;
e = ones(size(v));
p = N*R*(e./v)*t;

semilogx(v,p);
xlabel(’Volume mˆ3’);
ylabel(’Pressure Pa’);
6 2. BASIC CONCEPTS

title(’p(V)-plot at several isotherms’);


legend(num2str(t’));
ideal gas isotherms.m ends here
Everything is a matrix in Matlab, and depending on your attitude to linear algebra this
may be a relief or a nuisance. However, take advantage of this feature and try to eliminate
for-loops, if-tests, and other spaghetti-ingredients. My own experience is that Matlab-
programming may result in only 10% of the code compared to compiled languages like
FORTRAN and C++.

2. Heterogeneous containers (lists)


I first decided not to talk about lists, but after joggling back and forth with the code
I wrote for this course I finally decided to trouble you with one extra abstraction level.
Appearantly, we could have done without lists, but they make things easier, especially
in program interfaces. The problem is that Matlab has a dirty implementation of the list
concept called a cell array which makes it difficult to remember the syntax from one day
to the other. The big difference between a list and a vector is that vectors hold numbers
while lists can hold strings, lists, matrices, structs, etc. In Matlab there are a number of
functions that let you manipulate the transition from a list to a vector and back:
char abs char cellstr
list → character matrix → matrix → character matrix → list
Here, a character matrix is like any other matrix execpt that it contains numbers in the
range 0–255. If you display this matrix on screen you will see letters and not numbers.
However, you can still make use of the matrix as a numerical object, but once you manip-
ulate its content Matlab forget about ASCII-decoding and display plain numbers (unless
you explicitly tell something different). A short tour de lists follows:
snippet from matlab list.m starts here
clear;
format compact;

mylist = {’some’,’words’,’in’,’the’,’list’};

disp(’List syntax: mylist = {’’some’’,’’words’’,’’in’’,’’the’’,’’list’’}’);


disp(’This is how ’’mylist’’ looks:’);
pause;

disp(mylist);
disp(’Run size(mylist) to see the matrix-like size of the list:’);
pause;

disp([’size(mylist) = ’,num2str(size(mylist))]);
disp(’Run char(mylist) to convert to a character matrix:’);
pause;

disp(char(mylist));
disp(’The new size is:’);
pause;

disp([’size(char(mylist)) = ’,num2str(size(char(mylist)))]);
disp(’Convert to ASCII-numbers using A = abs(char(mylist))’);
pause;
3. USER-DEFINED DATA TYPES (STRUCTS) 7

A = abs(char(mylist));

disp(A);
disp(’Replace spaces (32) by periods (46)’)
pause;

i = find(A==32);
A(i) = A(i) + 14;

disp(A);
disp(’Convert back to a character matrix using char(A):’)
pause;

disp(char(A));
disp(’Convert into a new list using cellstr(char(A)):’);
pause;

disp(cellstr(char(A)));

matlab list.m ends here

3. User-defined data types (structs)


A struct is an extensible data type that Matlab has inherited from C. It is now ac-
cepted as a standard data storage facility in most programming languages, not only C and
Matlab. Compared to matrices, which are like dense tables, the struct is an open tree-like
container. The branches of the tree are given names by the programmer, and at the very
end of each branch sits a leaf which keeps a data object. An important feature of the
struct is its extensible and heterogenous nature which makes it ideally suited for object
oriented programming. This means the struct can hold several different data types at one
time; matrices, other structs, strings, etc. One example follows:
snippet from matlab struct.m starts here
book.author.name.given = ’Tore’;
book.author.name.family = ’Haug-Warberg’;
book.author.age = ’(now-datenum(’’13-Nov-1958’’))/365’;
book.title = ’The IKP Matlab companion’;
book.title.subtitle = ’Exercises in TMT4140 etc.’;
book.ISBN = 0;
matlab struct.m ends here
To figure out my age (uh-oh!) you can issue the command eval(book.author.age).
This operation is known as string parsing, see chapter 6 for an introduction to this fasci-
nating subject.
Structs can obviously be used to capture data in a systematic way, much like a book
with chapters, sections, paragraphs, etc. One specific use is to make programs less sen-
sitive to software upgrades. Imagine you have been asked to program the van der Waal
equation function[p]=vdw(v,t,n,tc,pc). Months later, when you have forgotten what you
did the first time, you are asked to make the model more general, say function[p]=vdw(v,
t,n,tc,pc,K), where K is an interaction parameter matrix. If the model was implemented as
function[p]=vdw(v,t,n,par) in the first place, this update had been trivial since you would
not need to do any changes to the program interface, just include one new field par.K in
the input and change the model accordingly.
8 2. BASIC CONCEPTS

4. Input/output issues
To save the current work space simply issue the command save. To load it back use
load. All variables in the workspace will then be written to/from a standard (binary)
file named matlab.mat. This is OK for day-to-day use, but you should know about one
possible pit-fall — you need Matlab installed to view the information in matlab.mat! To
have easier access to your data you must save the information in a text file rather than a
binary file. Fortunately this is also very easy, just issue the command save yourFileName
-ascii to save data with 8 digits, or save yourFileName -ascii -double to save data with 16
digits. You can also write formatted data to a file using the fprintf command, see the files
. . .fit.m for examples on how to generate a program from the inside of another program
(this is a quite powerful technique).
Plotting data in Matlab is a snap once you have become familiar with vectors and
matrices. In its simplest version you enter the command plot(x,y), where x and y are
two vectors of the same shape. There are numerous ways to produce labels, multiple
plots, 3-dimensional plots, etc. Take a look at the files . . .fit.m if you want to see some
examples.
5. Tricks of the trade
• Always start your script with the clear command to be sure you get a fresh start
(avoid overlapping workspaces).
• Function variables should always be entered explicitly as in z = f(x,y).
• Function parameters should be wrapped into a struct and given at the end of the
argument list as in z = f(x,y,s).
• Use long variable names e.g. Hungarian notation longNamesLikeThis at the top
level of a program, and successively shorter names deeper down in the program
hierarchy (i, j, x, y, etc. at the lowest level). Do not use underscore in variable
names.
• Use underscore in long function (file) names (long function name like this). Do
not use Hungarian notation for files names (Windows does not support case
sensitive naming).
• Segment the code into readable blocks. Consider using whole-line comments in
front of each block to explain the gross action of the code.
• Use right margin comments to explain complex expressions.
• Align the assignment operators in each block (the = operator often plays a par-
ticularly important role in mathematical programs).
CHAPTER 3

How to solve equations

1. Linear equations
Solving linear equations is all what engineering is about, at least this is not far from
the truth, and the importance of this chapter is so immense that you can hardly take it too
seriously. Matlab makes the solution of big equation systems a snap, but beware of the
dangers if you do not know exactly how the solver works. In the worst case you may get
fatally wrong results. This statement is quite harsh, so let us start out with one simple
example:

§ 2 You are asked to make 98 octane gasoline containing 1% aromatics. You


have three petroleum fractions at your disposal: Fraction one holds 90 octane with
0.2% aromatics, fraction two holds 105 octane with 2% aromatics, and fraction three
holds 95 octane with 0.5% aromatics. The octane number is a mass linear function
of each petroleum fraction. Set up an equation system Ax=b that can be solved using
Matlab. Invert the equation system by hand (row elimination), and compare with
the Matlab solution x=inv(A)*b.

98  . We are given two pieces of information (octane number and aro-
matic content) which expresses two equations in three unknowns. The total amounts of
each fraction (in tons, kilograms or whatever) has no importance, which means we can
do the calculations on a normalized basis. This gives us the third piece of information
needed to invert the equations:
    
 90 105 95   a   98 
 0.2 2 0.5   b  =  0.96 
    
1 1 1 c 1
The Matlab-script listed in Appendix C.2 takes you through the elimination process, step
by step. Notice that “hand-elimination” yields more accurate results than Matlab inver-
sion (this is not a general result though). The difference is barely visible in this case, but
in some practical problems like e.g. chemical process simulation there maybe thousands
of variables, and the differences between two numerical solutions can be like day and
night. Therefore, always check your result by back-calculating the right hand side! 
So far so good, but things are quite different when working on a computer compared
to doing hand calculations. In Section 2.1 I told you that the computer has only a limited
range of numbers available. From time to time you will therefore experience that Matlab
complains about singular matrices or bad condition numbers. Without any understanding
of the possible causes of these messages you are totally lost and may easily produce
garbage results. The next exercise gives you a clue of what appears to be a common
pitfall.

§ 3 Change the aromatic analysis in the last example to 1 − 10−15 , 1, and 1% for
the three gasoline fractions. What happens to the solution now?
9
10 3. HOW TO SOLVE EQUATIONS

M  98  . The Matlab script is unchanged from the last exercise
(your prompt answer decides what to do). The first thing you should notice is the neg-
ative (nonphysical) element in the solution vector [−0.1583, 0.2208, 0.9375]. Next you
should not take too easy on Matlab’s warning message: “Matrix is close to singular or
badly scaled—Results may be inaccurate”. Finally, you should recognize that the back-
calculated Matlab solution [51.25, 0.5, 0.5] is pure nonsense. 
By now we have solved one nice and clean equation system, and we have modified it
into something ill-conditioned. Next, let us take the full step and look at a truely singular
problem. This may look terrifying, but the important message is: Don’t panic∗! You are
told to solve the equations and should focus on your task without too much hesitation.

§ 4 Solve the component balances of this flowsheet as a simultaneous set of equa-


tions Ax = b, where x = (ṅ1 , ṅ2 , ṅ3 , ṅ4 , ṅ5 ) and ṅi [mol s-1 ] are the molar flow rates of
the streams i ∈ {1, 2, . . . , 5}. Write the solution as
x = x p + Nxh
where x p is a particular solution and xh is the (homogeneous) solution Axh = 0. Plot
the equilibrium quotient Q = x2B /xA in stream 3 as a function of the recirculation
rate. Determine the smallest recirculation flow that is theoretical possible consider-
ing that the equilibrium constant is K = 0.74.

F 2.8  S’ . You are given a flowsheet with 10 unknowns and 10
equations, but the coefficient matrix is singular! Instead of one unique answer you have
infinitly many possible answers, which in practise must be settled by knowing some extra
information. In this case it is the conversion constraint Q = x2B /xA ≤ K = 0.74 for the
reaction A → 2B. This is a non-linear constraint which we shall not devote time on
right now, but we can easily plot Q as function of the recirculation rate and determine an
approximate region for possible plant operation (Appendix C.3). 
In all the examples we have met so far there have one way of expressing the equations
— the free variables have been unknown and the specifications have been fixed. Some-
times, however, you will need to solve an partially inverted specification problem, i.e. an
equation system
Ax = b
where some of the x’s are known and a similar number of the b’s are unknown. I have
coined the term “partially inverted problem” for this behavior, because in the ultimate
case all the x’s are known and you do not need to solve any equations at all (the inverted
problem is formulated explicitly).

§ 5 Write a function [x,b]=partialinv(A,x,b) which solves a partially inverted


equation system. Let x(i) = b(j) = NaN denote the free variables x(i), and the spec-
ifications b(j), that are considered unknown (on input). Update the vectors x and b
such that Ax=b on output.

P   . You may wonder why it is necessary to spend time on
writing a function in this case. After all, re-ordering the variables (and the specifications)
will solve the problem. If it is a one-time problem this is definitely the right strategy,

Yes, I have admittedly taken this pun from the hilarious trilogy (in five volumes): A Hitch-hiker’s
Guide to the Galaxy by Douglas Adams.
1. LINEAR EQUATIONS 11

T 3.1: Production data for a typical nitro-phosphate


fertilizer plant.

Component Case I Case II


Ammonia 1300 ton d 1300 ton d-1
-1

Mono-ammonium phosphate 200 ton d-1 200 ton d-1


Calcite − 0
Calcium nitrate tetrahydrate 200 ton d -1

Oxygen (output) 0 0
Carbon dioxide (input) 0 0
Water (input) 100 ton d-1 0

but if the equations are part of a more general problem setup, it can be easier to keep
the coefficient matrix unchanged, and flag the x(i)’s and b(j)’s as suggested above (see
Appendix C.4). 

In process simulation you will find that most of the unit operations are without chem-
ical reactions. Hence, simulating a complete chemical plant will most of the time mean
that the mass balance and the component balance are equivalent concepts. However, if
you view the plant from the outside and just look at the net reactions going on in its
complex inner, you will frequently find that the atom balance is the key concept. One
example follows:

§ 6 The chemistry of a nitro-phosphate fertilizer plant is quite complex and in-


volves several steps of leaching, evaporation, neutralization, etc. The main reactions
are

NH3 + 2O2 HNO3 + H2 O


2NH3 + Ca3 (PO4 )2 + 6HNO3 3Ca (NO3 )2 + 2NH4 H2 PO4
3H2 O + CaCO3 + 2HNO3 Ca (NO3 )2 × 4H2 O + CO2
HNO3 + NH3 NH4 NO3

where NH3 , O2 , Ca3 (PO4 )2 , CaCO3 , H2 O and CO2 are considered to be (possible)
reactants, and Ca (NO3 )2 × 4H2 O, NH4 H2 PO4 , CO2 , NH4 NO3 , O2 and H2 O are (pos-
sible) products. Note that H2 O, O2 and CO2 appear as both reactants and products
(the recipient act as a buffer). Your task is to calculate all input and output flows
given the production data in Table 3.1. Hint: Let ẋ and ẏ be vectors of reactant and
product flows respectively, and A and B the corresponding formula matrices. Make
sure your definitions are compliant to Aẋ = Bẏ. You can then choose to solve either
B−1 Aẋ = ẏ or A−1 Bẏ = ẋ using the partial inversion algorithm from the last example.

F . Nothing really new here, except that you have to specify two coef-
ficient matrices in order to solve one equation system (Appendix C.5). 
12 3. HOW TO SOLVE EQUATIONS

2. Independent reactions
The calculation of mass conservation due to chemical reactions is tightly coupled to
linear algebra. Consider the so-called formula matrix for the system CO–H2 O–CO2 –H2 :
 
 0 2 0 2 
A = (atoms × species) =  1 0 1 0 
1 1 2 0
Given a mole number vector n for the species mentioned above, we can calculate the mole
numbers of the atoms from the standard matrix product b = An. For all reactions taking
place in a closed system we know that the atoms must be conserved (not talking about
nuclear reactors here), and if the changes in the species mole numbers are represented by
∆n this leads to
∆b = A∆n = 0.
The next step is to find a general solution to this problem. The full-blown theory belongs
to a course in linear algebra, but from physical reasoning we can argue that ∆n must be
a function of the independent reactions of the system. Hence, if we let x represent the
extents of (independent) chemical reactions, and N the reaction stoichiometry matrix, we
can write
∆n = Nx.
Combining the last two equations, and realizing that x is by definition a free vector vari-
able, we get the necessary condition
AN = 0.
By standard row elimination, and column permutation if this proves necessary, matrix A
can be factored into  
I B
A→
0 0
 
Thus, by setting N = B −I we obviously have a stoichiometric matrix N which
fulfills the mass balance equation AN = 0. Neat, isn’t it?

§ 7 Find a set of independent reaction equations that fully describe monoprotic


acid–base titration:
HA + B  A− + BH+
The equilibrium reactions are assumed to take place in an aqueous environment and
you should therefore end up with 3 equations.

A- . The Matlab code listed in Appendix C.6 will assist you in get-
ting the reaction stoichiometry right, but traditional hand calculations are perfectly OK.


3. Linear parameter estimation


The issue in this section is to find the minimum sum-of-squares of a function that
depends linearly on the coefficients. Let the sum-of-squares function be
n
s= (yi − f (xi , c))2 ,
i=1
3. LINEAR PARAMETER ESTIMATION 13

where yi and xi = (xi,1 , xi,2 , . . . , xi,n ) are the experimental observations, and c = (c1 ,
c2 , . . . , cn ) are the parameters of the model f (xi , c). If the sum-of-square function shall be
a minimum one with respect to the parameters c1 , c2 , . . . , cn we must show that
∂s ∂s ∂s
= = ... = = 0.
∂c1 ∂c2 ∂cn

Provided the model f (xi , c) is linear in the parameters we can write fi = j ai j (xi )c j , and
for s we get the expression:
 2
n 

n 
s= yi − ai j (xi )c j  = (y − A (x) c)T (y − A (x) c)
i=1 j=1

I have deliberately chosen a matrix definition of the function, because this is one of the
key issues in this course: Try to think in terms of matrices and vectors if at all possible!
Differentating s with respect to ck and putting the result equal to zero yields
 
∂s n 
 n 
− =2 yi − ai j (xi )c j  aik = 2A (x)T (y − A (x) c) = 0,
∂ck i=1 j=1

or simply
 −1
c = AT A AT y.
These are the so-called normal equations∗ of the system A(x)c = y. Note that the equation
system is over-determined, i.e. there are more observations (equations) than parameters.
Thus, there will be no solution except if the observations are in perfect agreement with
the experimental data. Such coincidence never happens in practise and we must therefore
look for an inexact solution. Among all the alternatives we shall go for the solution that
minimizes the Euclidean length of the observed deviations yi − f (xi , c).

§ 8 Fit the coefficients ci∈{1,2,3} in the expression log µ = c1 + c2 T −1 + c3 T −2 to


µ, T -data found in water viscosity 1bar data.txt see Appendix E.3

L . You may think this is a non-linear problem, but no! Even though µ
is a non-linear function in T it will still be a linear function in the coefficient vector c.
The formula matrix is
 
 1 T 1−1 T 1−2 
 ..  ,
A (T ) =  ... ..
. . 
 
1 T n−1 T n−2
 
and the corresponding observation vector is y = log µ1 , . . . , log µn . A Matlab script for
solving the least square problem is given in Appendix C.7. 

§ 9 Fit the coefficients ci∈{1,2,3,4} in Wagner’s vapor pressure equation to p, T -


data found in water vapor pressure.txt see Appendix E.1. Wagner’s equation can be


Actually, Matlab is capable of solving such problems directly with the special “operator” c = A\c but
the backslash means several things depending on the arguments and we shall not pursue this alternative any
further.
14 3. HOW TO SOLVE EQUATIONS

written:
def
T r log Pwagner
r = c1 τ + c2 τ1.5 + c3 τ3.0 + c4 τ6.0
def
τ = 1 − Tr
def T
Tr =
Tc
def p
pr =
pc
The critical constants of water are T c,water = 647.1 K and pc,water = 220.64 bar.

V . Don’t let this seemingly complex model scare you! Note carefully
that the function T r log pwagner
r is linear in the coefficients c1 − c4 . You can therefore use
standard linear parameter estimation theory if the observed T, p-data are converted to
T r log pr and τ. This yields
 
 τ1 τ1.5 τ31 τ61 
 .. ..  ,
1
A (T ) =  ... ..
. . . 
 
τn τn τ3n τ6n
1.5

and  
 T r,1 log pr,1 
 .. 
y =  . 
 
T r,n log pr,n
The Matlab code is given in Appendix C.8. 

§ 10 Fit the coefficients c1 and c2 in the expression ρ = ρmax ec1 τ ec2 τ to ρ, T -data
1.3 1.6

found in water density 1bar data.txt see Appendix E.2. The definitions of τ and ρmax
are:
 
τ= 

T
− 273.15 − 3.98
[K]
−3
ρmax = 999.97490 kg m

L . As before, the trick is to transform the equation; this time to log(ρ/
ρmax ) = c1 τ1.3 + c2 τ1.6 . The rest is standard, see Appendix C.9. 

4. Polynomials
Easy to understand, easy to manipulate, and easy to calculate — there are many rea-
sons why polynomials appear in engineering calculations, e.g. when an exact solution
is missing or for some reasons out of scope for numerical work. However, polynomials
may also be the outcome of theoretical investigations as shown in the pH-calculation dis-
cussed below. Dealing with such problems it is important to know that polynomial root
finders are very stable, but that it may sometimes be difficult to interpret the physical root
among the several false ones.
In Ex.7 we discussed the independent reactions of monoprotic acid-base titration. The
net reaction equation was
HA + B  A− + BH+
5. SINGLE NON-LINEAR EQUATIONS 15

Assume that the initial concentration of the base (in the flask) is C 0B , and that the acid is
being added in arbitrary amounts. The nominal∗ concentration of the acid C HA is then
a free variable. Eliminate the other variables in the equation system till you end up
with P4 (C H + ) = f (C 0B , NHA , k1 , k2 , k3 ), where ki∈{1,2,3} are the equilibrium constants and P4
stands for a 4th degree polynomial.

§ 11 Write a Matlab script that calculates pH as a function of the nominal acid


concentration using ca=linspace(0,2*cb,1000), where cb is 0.1 mol l-1 . Neglect possi-
ble volume changes during this “numerical experiment”.

H-. There are infinite many choices of independent reactions, but a nice
choice is the following one (H+ appears only once and this makes the elimination process
easier):
x
HA + B  BH+ + A−
y
H2 O + B  BH+ + OH−
z
H+ + B  BH+
The extents of reaction x, y, z (in the right direction) can be used to express the mass
balances as shown below:
C BH + COH − (x + y + z) y def
= 0 = C H2 O 10−pKb = k1
CB CB − x − y − z
C A− C H + −xz def
= = 10−pKa = k2
C HA CA − x
def
COH − C H + = −yz = C H2 O 10−pKw = k3
Elimination of x and y gives
   
−k1 z4 + k1C 0B + k3 + k1 k2 z3 + k1 k2C HA + k1 k3 − k1 k2C 0B − k2 k3 z2
 
− k2 k3C HA + k32 + k1 k2 k3 z + k32 k2 = 0,
which can be solved repeatedly to yield the titration curve for the acid–base pair. At each
titration point we have to choose among four possible solutions. There are no clues as to
which of the roots is the physical one, but in this case it appears to be the negative root
(Appendix C.10). 

5. Single non-linear equations


There exist several “general-purpose” equation solvers in Matlab, but their mathe-
matical methods are well beyond the current scope. Regretfully so because we are then
reduced to ordinary users of advanced code, which in turn makes it hard to tell what is
clever and what is dumb. I mean, how could we possibly tell without knowing the under-
lying theory? An important concept in this chapter will be the functional that is discussed
more carefully in Chapter 5. It is achieved in this context by the function handle operator
@ which lets the user specify a run-time definition of the equation to be solved. The
necessary actions are then taken by the solver through the built-in function feval which
is used to run a user specified function with solver specific variables. This is a good
example on the “tool-box” idea of Matlab.

Nominal means measured before any reactions take place.
16 3. HOW TO SOLVE EQUATIONS

§ 12 Calculate the pressure drop over a L = 2000 m long pipe transporting


Q̇ = 0.5 m3 min-1 of water. The pipe (D = 5 cm) is made of commercial steel. The
temperature of the water is θ = 8 ◦ C. Use density and viscosity functions from Ex.19
and Ex.17. Hint: Colebrook’s equation for the friction factor is:
 
1  ε 2.51 
 = −2 lg  +  
f 3.7 · D f Re
2
f Lv
∆p = [m H2 O]
2Dg
Use function fzero to solve this equation inside your pressure drop calculation. Hint:
write a function colebrook(lnf,eod,lnRe) which returns the residual on the form∗:
  
1   e 2.51 
log ( f ) + log −2 lg  D +   
2 3.7 exp 1 log( f ) + log (Re)
2

P-. The friction factor can be solved explicitly as lnf = fzero(@cole-


brook,lnf,opt,eod,lnRe) where opt=[’display’,’iter’] can be used to display the iteration
progress. The Matlab code for the Colebrook residual is given in Appendix C.11, and for
the pressure drop calculations in Appendix C.12. 
This exercise illustrates an extremely important issue in non-linear equation solving.
In theory any residual function that evaluates to zero at the solution point is sufficient
for finding the correct answer, but in practise only a few residual functions will be same.
Finding a good residual is an art, but the following rules of thumb may be of value:
(1) Make sure the residual is comparable to 1, i.e. 10−6 should be considered a small
residual and 106 a big residual. This can of course be achieved by pure scaling.
(2) Make sure the gradient has comparable magnitude in all directions (at least close
to the solution point).
(3) Residuals that are appealing to the human eye are not necessarily what makes
your algorithm effective.
Finding one single root of a function is usually not a big problem, but when the issue is
to build a more general function these rules may become important (see Exercise 13).

6. Sets of many non-linear equations


§ 13 The inverted variant of Ex.12 is to calculate the volumetric flow rate for a
given pressure drop. This calculation is a little more involved because there are two
non-linear functions to be solved simultaneously (Re = ρvD/µ):
L v2
∆p = ρ f
D 2 
1  ε 2.51 
 = −2 lg  +  
f 3.7 · D f Re

F-. The same procedure as in Ex.12, except that we must call fsolve rather
than fzero. In the function call I have chosen to define a struct for copying the parameters.
This is much easier than to remember explicit parameter ordering in the function call

It took me two full days to convince myself that there is no way to avoid the logarithmic form.
However, feel free to try other residual forms and prove that I am wrong!
6. SETS OF MANY NON-LINEAR EQUATIONS 17

(just try to remember the order of six parameters for more than five minutes). I have
also taken the trouble to vectorize the calculations in order to be prepared for future
demands. The solution is this time written x = fsolve(@friction and reynold,[lnRe,lnf],
opt,@colebrook,s); where lnRe=x(:,1) and lnf=x(:,2) on output. The Matlab code for
the two flow residuals is listed in Appendix C.13, and for the flow rate calculations in
Appendix C.14. 

§ 14 From fluid mechanics you know that turbulent flow develops at Re  2300.
Write a Matlab script that reveals the transition from laminar to turbulent flow.

T   . Needs a f -relation for laminar flow which can be
compared with Colebrook’s function in Ex.12, i.e. f = Re 64
. This relation is explicit in f
and there is no need for a non-linear solver, but who cares since the point here is to learn
about solvers (see Appendix C.15)! The flow rate calculations comparing laminar with
turbulent flow are found in Appendix C.16. 

§ 15 Hallvard Svendsen, Ex.7: Compressible friction flow.

C . Not implemented. 


CHAPTER 4

Write your own functions

1. The function concept


When you start Matlab you will enter (the topmost) workspace. From there, you can
enter commands at the keyboard, or you can import several commands at once from a
script file, in order to build up the content of your workspace. You can also make calls to
external procedures (called functions in Matlab). When a function has finished its job it
will return to the workspace, hopefully with some results. Functions may even call other
functions, but eventually the control will be returned to the topmost workspace. Note,
however, that all variables passed back and forth in a function call is done “by copy”:
In fact, entering x=exp(3) into Matlab, copies the number 3 into the exp function,
which returns a copy of the result to the variable x. The exp function does not change
the number 3 in any way! To illustrate this further let us try the command sequence
x=3; x=exp(x). In this case the variable x is first asked to hold a copy of the number 3.
Thereafter, the value of x (which is still 3) is copied into the exp function, and the result
is finally copied back into x. In this case x really did change, but only because we told it
explicitly to do so. This is called imperative programming.

§ 16 Write a function chon(x,y,z,w) for calculating the molecular weight of the


fictitious compound Cx Hy Oz Nw .

M   CHON-. See Appendix C.17. 

2. Vector functions
By vector function I mean a function that calculates more than one output value. Typ-
ically, these functions should mimic the shape of their input arguments. As an example
take the built-in function exp. If you enter something like x=[1 2; 3 4]; y=exp(x); from
the keyboard, you will get an y-matrix with the same shape as x. This is veeery handy
and is certainly something you should pursue when you write your own functions.

§ 17 Make a Matlab function that calculates log µH2 O = c1 + c2 T −1 + c3 T −2 for an


arbitrary temperature matrix t. The function syntax is water viscosity 1bar(t) and
the parameters are c = [-8.0003593134, -1470.7557834, 526396.01377] see also Ex.8

W . The trick is to inherit the shape of the temperature argument in the
function body. The matrix e=ones(size(t)) will do this, as shown in Appendix C.18. 

§ 18 Make a Matlab function that calculates log pwagner


water = f (T ) for an arbi-
trary temperature matrix t. The Wagner equation is described in Ex.9. The func-
tion syntax is water vapor pressure(t) and the parameters are c = [-7.78664494819,
1.50070473755, -2.82073715777, -1.20214640863]

19
20 4. WRITE YOUR OWN FUNCTIONS

W  . Same trick as in Ex.17, see Appendix C.19. 

§ 19 Make a Matlab function that calculates ρwater = ρmax ec1 τ +c2 τ for an ar-
1.3 1.6

bitrary temperature matrix t. The function syntax is water density 1bar(t) and the
parameters are c = [0.00003932621, -0.00003868077], see also Ex.10.

W . Same trick as in Ex.17, see Appendix C.20. 

3. Iterative functions (algorithms)


The K-value method for solving 2-phase equilibria consists of solving the equations
yi = Ki xi and (1 − α)yi + αxi = zi for all components i ∈ [1, n] in the mixture. Normally,
yi and xi will be the mole fractions of component −i− in the vapor and liquid phases re-
spectively, and α will be the mole fraction of the liquid phase (i.e. the number of moles
in the liquid phase compared to the total numbers of mole present in both phases). Fid-
dling around with the symbols it can be shown that everything boils down to solving one
non-linear equation in α:
z (1 − K )
i i
f (α) = =0
α + (1 − α) Ki
After this equation has been solved the two mole fractions can be calculated explicitly:
zi
xi =
α + (1 − α) Ki
Ki
yi =
xi

§ 20 Write a function [x,y,l] = rachford rice(z,k) that calculates the component


mole fraction vectors x and y along with the phase mole fraction of the first phase
(i.e. the phase from where the x is taken). On the input side z is the total composition
vector and k is the vector of K-values.

R-R. This problem is ideally suited for Newton’s method because it turns
out that the merit function is monotonically decreasing:
∂f  1 − Ki
2
=− zi <0
∂α α + (1 − α) Ki
The implementation is therefore straight forward, see Appendix C.21. 

4. Recursion — good, evil or maybe bad?


A favorite example on recursive programming is the calculation of factorials. The
factorial n! can obviously be programmed using a for-loop, but a “cleaner” alternative is
the recursive call procedure:
snippet from recursive factorial.m starts here
function [fac] = recursive_factorial(n)
if (n>0)
fac = n*recursive_factorial(n-1);
else
fac = 1;
end
4. RECURSION — GOOD, EVIL OR MAYBE BAD? 21

recursive factorial.m ends here


def
Another favorite is the calculation of the Fibonacci sequence F n = F n−2 + F n−1 .
The Fibonacci numbers derived from F 0 = 1 and F 1 = 1, and other sequences built
on the same principle, appears in surprisingly many fields of science like e.g. biology,
number theory, architecture, optimization theory, chemistry, etc. The code listed in (re-
cursive randmine) uses the Fibonacci sequence to generate random numbers given the
two start values 0.8 and 0.0 and the imposed rule that all addition is modulo 1. This
means we shall not be interested in the magnitude of the number, just the fractional part
of it.
snippet from recursive randmine.m starts here
function [x] = recursive_randmine(n)
if (n>2)
x = recursive_randmine(n-1) + recursive_randmine(n-2);
else
x = 0.6 + 0.2*n;
end
x = x - floor(x);
recursive randmine.m ends here
Whereas n! eats CPU-time in proportion to n, F n is much more greedy. It is in fact
the worst kind of application you can possibly write because the CPU-time grows expo-
nentially with n, look at Table 4.1 for details. Another interesting observation concerning
the modified Fibonacci sequence is its periodicity. Look carefully at the list generated
below,
n 1 2 3 4 5 6 · · · 19 20 21 22 23 24
mod(F n , 1) 0.8 0.0 0.8 0.8 0.6 0.4 · · · 0.6 0.2 0.8 0.0 0.8 0.8
and you will see that the sequence repeats itself after 20 calculations. In other words:
F 21 = F 1 , F 22 = F 2 , and F 23 = F 3 . Since the recursion needs only two members F n−2
and F n−1 to calculate F n it is sufficient to observe the repetition of three numbers in or-
der to prove that the entire sequence will repeat. Another feature is that the sequence is
reproduced each time it is evaluated, irrespective of the programming language, the pro-
grammer or the computer. This is the reason why random numbers produced by generic
formulae are called pseudo-random. So, what has all this to do with chemistry students?
A lot really, since random numbers are used heavily to:
(1) Replace observations of random nature, e.g. add “white” or “pink” noise to other
simulations in order to produce more realistic results.
(2) Test algorithms. I cannot possibly think of any better way of testing an algorithm
than to let it work on a massive set of random input data.
(3) In statistical theory like statistical mechanics, molecular dynamics and Monte
Carlo methods.
(4) In optimization theory, i.e. “simulated annealing” techniques used in e.g. process
optimization.
(5) Make you work with individual problem solutions in this course.
One comment about the last item: To make sure I will be able to verify your results
(on midterm exams), we must use the same random number generator and I have to
control the “seed” you use to start the sequence. This is the reason you should implement
“randolph” listed in Appendix C.1.
Not all programming languages open up for recursive definitions (e.g. FORTRAN-
77), and the reason is very simple: If you forget to test the input arguments properly,
the function will call itself forever! It is like executing the loop while(1>0) without
22 4. WRITE YOUR OWN FUNCTIONS

T 4.1: Calculation of


Fibonacci-numbers using re-
cursive function calls. Note
exponential growth in CPU-time.

n mod (F n , 1) time[s]
1 0.8 0.000
.. .. ..
. . .
14 0.2 0.020
18 0.6 0.171
22 0.0 1.101
26 0.4 7.500
30 0.8 51.38

breaks, but because things are less transparent when using function calls such ill-defined
recursiveness can be hard to debug.

§ 21 Solve the problem y = x2 using recursive programming. The function syn-


tax is x = recursive sqrt(y,x0), where x0 is a user supplied start estimate for the
algorithm. Hint: The Newton method gives rise to 2xδx + x2 − y = 0. From this
scheme we can write an explicit update of xk+1 like this:
 
1 y
xk+1 = + xk
2 xk
 
S  . One possible recursive update is x = recursive sqrt(y, 12 yx + x ),
and this really works! E.g. evaluating recursive sqrt(2,6.023e23) yields the correct
√ an-
swer 1.4142 . . . after 84 calls (the Avogadro number is a rather poor estimate of 2). The
code from recursive sqrt is shown below: 
snippet from recursive sqrt.m starts here
function [x] = recursive_sqrt(y,x)
if (abs(x*x-y)>eps*y)
x = recursive_sqrt(y,(y/x+x)/2);
else
x = x;
end
recursive sqrt.m ends here
You may wonder why you should bother about recursive definitions at all since the
applications we have met so far are rather trivial. My advice is: Recursive calculation
is very nice if you are able to prove convergence a priori, or if you are interested in the
mathematical behavior of the solution, or if you are interested in compact definitions (this
may yield a tremendous increase in program readability if your algorithm is complex).
Besides, recursiveness is in the heart of declarative (functional) programming. However,
since function calls are much more expensive than arithmetic operations (+, i, ∗, /), mas-
sive recursiveness should be avoided if the function overhead steals excessive CPU-time.
CHAPTER 5

Functionals or function(function)s

A functional in this context means a function that takes another function as input and
produces a number. Examples are: Definite integrals, minimization procedures, partial
diffentials, Taylor expansions, etc.

1. Integration
§ 22 The velocity profile in a circular duct is needed to calculate the average
volumetric flow of gas. A series of pitot-tube measurements gave the following result
where the dynamic pressure is in mm fluid head:
hNS 4.7 10.7 18.3 20.5 20.5 23.3 29.6 20.4 16.2 11.8
=
hEW 2.1 8.6 15.4 16.2 21.3 21.3 20.5 16.8 13.3 2.2
The gas has molecular weight 28 gmol−1 , temperature 110 ◦ C and pressure 1 bar.
The density of the sealing fluid is 850 kgm−3 . The cross-section is divided in five
concentric rings, all with the same area (four measurements in each ring). The total
diameter of the duct is 1.6 m. Calculate the volumetric flow in m3 /h using Simpson’s
integration rule, confer function quad.

P-. The determination of gas velocities in large ducts and chimneys is quite
regularly done with a pitot-tube. From several measurements at different radial positions
the velocity profile is easily constructed. In this particular case we have measurements
in the North-South and East-West cross sections. If we average the measurements the
velocity profile can be based on polynomial approximation. We can e.g. assume laminar
flow (very wrong!) and thereby ask for a parabolic velocity profile. Then a second order
polynomial is correct and the function polyfit suffices. However, the velocities at the
boundaries are not zero, see Appendix C.23! A better fit is obtained by increasing the
number of parameters in the polynomial, but remember that higher order polynomials can
oscillate violently (even inside the fitted region). The result may become terribly wrong
although in the current example it is not too bad. Alternatively we could give up every
analytical effort and go for a cubic spline interpolation. This time the velocity profile
becomes flat i.e. the flow is turbulent, but the spline will allways go through all the points
so it is not possible to jugde how accurate the “fit” is. It may still be a useful tool to get
an idea of shape of the profile, however. 

2. Ordinary differential equations


When Chemical Engineers face up to model and simulate a given system, it seems
that a major concern is whether the ODE-solver will work. This turns into a nightmare
when things go wrong and it is really disappointing when the computation crashes. Most
often the problem is that we fully trust the “stupid” built-in code to do the whole job for
us. In order to solve their simulation models, Chemical Engineers usually deal with ex-
plicit first-order systems of differential equations (ODEs) with algebraic side constraints,
23
24 5. FUNCTIONALS OR FUNCTION(FUNCTION)S

turning the problem into a system of differential–algebraic equations (DAEs) of the form:
f (dx/ dt, x, t, u, y) = 0 where x is the set of n differential variables, y is the set of m alge-
braic variables, u is the set of k input variables, and f is the set of n + m DAE equations.
The solution of such a problem requires two steps:
(1) Defining and solving for the initial state x(0) of the system at t = 0 (initial time).
(2) Numerical integration of the DAEs from t = 0 to t (final time).
The second step is generally straightforward for simple systems. The challenge is
to consistently initialize the DAE system which means to solve step 1 above. If not
performed well it may cause the system to diverge in step 2. However, a DAE system
might be easier to deal with than a pure ODE system because the extra equations give
degrees of freedom we can use in the initialization. E.g. if the temperature evolution is
constrained by an energy balance it is easier to initialize T such that the energy balance
is fulfilled, than it is to solve the non-linear energy equation with respect to T as would
be required in a pure ODE set-up.

§ 23 Consider a gas A that dissolves into liquid B and diffuses isothermally in the
liquid phase. During the diffusion A undergoes an irreversible first order homoge-
nous reaction A + B → AB. If the mixture is treated as a binary solution, ignoring
AB, the mass balance can be written:
d cA
DAB − k1 cA = 0
d z2
This equation can be solved with the boudary conditions z = 0, cA = cA0 and z = L,
d cA / d z = 0. The equation can be rewritten into dimensionless variables

d2 Γ
(5.1) 2
− φ2 Γ = 0

with boundary conditions ζ = 0, Γ = 1 and ζ = 1, dΓ



= 0, and ζ = 0, Γ = 1 and ζ = 1,
Γ = 0. Solve the equation numerically and compare the solution you get to the exact
solution given by

(5.2) Γ = C1 cosh(φζ) + C2 sinh(φζ)

D. Any ODE function in matlab will produce the solution to this problem
with no problems. ODE functions can only solve (systems of) first order ordinary dif-
ferential equations. This problem is of second order. This can easily be rewritten to a
system of two first order equations. y + y + y = 1 can be written

u1 = u2

u2 = 1 + u1 + u2
Another consideration of this problem is the fact that the ODE solvers only support initial
conditions. Here, one initial condition is given, and one boundary condition. In order
to satisfy the initial conditions one have to iterate as shown in Appendix C.22. The
discrepancy between the numerical and analytical solution comes as a consequence of
the boundary conditions not being satisfied completely. 
4. OPTIMIZATION WITH CONSTRAINTS 25

3. Unconstrained optimization
§ 24 Terje Hertzberg: Non-linear parameter estimation.

N-  . Not implemented. 

4. Optimization with constraints


A thermodynamic equilibrium state is always optimal, i.e. it is either at a minimum or
a maximum of the pertinent thermodynamic state function. Exactly which state function
we are talking about depends on the constraints, and e.g. for ideal gas combustion it is
correct to minimize Gibbs energy:
minG(T, p, n)
n
An = b.
Note that the minimization is subject to n only, keeping T and p constant during the
calculation. There are several methods available for solving linearly constrained minima,
but my favorite is the Newton-Lagrange scheme which can be derived from the so-called
Lagrange function
 n 
m  
L=G− λi  Ai j N j − bi  = G − λT (An − b) .
i=1 j=1

By differentiation L with respect to Nk and λl at constant T, p, and putting the partial


derivatives equal to zero, we end up with the following equations describing the thermo-
dynamic equilibrium:
∂L
= µ − AT λ = 0
∂n
∂L
= An − b = 0
∂λ
These stationary conditions are finally solved by Newton’s method:
 ∂µ    T 
A T δn A λ − µ
(5.3) ∂n T
=
A 0 −δλ b − An

§ 25 Write a function [n] = mingibb(n0, T, p, mu0, A) which solves Eq.5.3 itera-


tively for an ideal gas system. The chemical potential vector of an ideal gas is
P 
µig = µ◦ + RT log ◦ N −1 n
 P 
n = N1 N2 . . . Nn

N= Ni ,
and the Hessian matrix:
 −1 
 ig  N1 
∂µ   RT
= H = RT  ..
def ig
.  − I
∂nT   N
Nn−1
26 5. FUNCTIONALS OR FUNCTION(FUNCTION)S

G  . Once you master vector/matrix notation, the calculations
are straight forward, but you must remember to test for negative mole numbers. The
algorithm will quite frequently take you into the unphysical region and the question is
what to do then. Many things can be said about this topic, but it appears that in this
special case it will be sufficient to shorten the step to, say, a fraction 0.9 of the maximum
allowable step, see Appendix C.25. 

5. Process control
Process control is an engineering discipline that deals with architectures, mecha-
nisms, and algorithms for controlling the output of a specific process (from Wikipedia
The Free Encyclopedia). Applications are found almost everywhere e.g. in the chemical
process industry, in living organisms and in robotics. Here we shall deal with one brief
example taken from the control of chemical reactors. The essential steps in developing a
control structure include the following:
(1) Objectives: Study the physical behavior of the system and decide on the control
objectives.
(2) Modeling: Build a mathematical model and simplify if necessary (either from
experimental data using identification techniques, or from physical equations
describing the plant dynamics).
(3) Controllability: Decide which variables are to be controlled (identify the manip-
ulated and measured variables and which links should be made between them).
(4) Structure: Decide on the measurements and manipulated variables (what sensors
and actuators will be used and where shall they be placed).
(5) Design: Select the control configuration and decide on the type of controller to
be used (formulate a mathematical design problem which captures the engineer-
ing design and synthesize a corresponding controller).
(6) Analysis: Decide on performance specifications, based on the overall control
objectives (assess the control system by analysis and simulation against the per-
formance specifications or the designers expectations).
(7) Implementation: Simulate the resulting controlled system (either on a computer
or a pilot plant).
In the following example we use steps one to four to study a simple reactor controller.

§ 26 A continuous stirred tank reactor (CSTR) has variable feed qin and variable
heat load Q. In the stationary state the incoming fluid has temperature T in = 350 K,
concentration C A,in = 2 kmol m−3 and volume flow q in = 1 m3 min−1 . The correspond-
ing heat load and reactor temperature are Q = 5000 kJ min−1 and T = 400 K
respectively. The (only) first order reaction taking place is A → B. The reaction rate
r = kC A follows the Arrhenius law
 
k = k◦ e− R T − T◦
E 1 1

where k◦ = 0.5 min−1 , E = 20 kJ mol−1 , R = 8.31453 J mol−1 K−1 and T ◦ = 400 K. The
task is to control the output concentration C A using qin and Q as control variables.
The temperature T in and concentration C A,in are disturbances to the process. There
is no B in the feed. Other (constant) data are: reactor volume V = 4 m3 fluid density
ρ = 1000 kg m−3 and heat capacity CP = 0.15 kJ kg−3 K−1 .
5. PROCESS CONTROL 27

CSTR. The Matlab code in Appendices C.26, Appendices C.27 and Appendices C.28
produces four plots. The steady state is first verified (plot 1) before a series of dynamic
responses to some step changes and disturbances are calculated (plot 2). The model is
then linearized and the state-space matrices A, B, C, D, E and F are calculated along
with the controllability, the observability and the stability of the model. Finally, the code
generates the transfer function and calculates its poles and zeros, and the RGA in different
frequencies (plot 3 and 4).

CHAPTER 6

String parsing

1. Chemical formula arithmetics


Consider a simple chemical formula like H2 O. What does it tell us? Of course you
know the answer; take two atoms of hydrogen and one atom of oxygen, combine and
you have water. However, I am quite sure you have never reflected over how close the
chemical formula is an arithmetic expression! E.g. the expansion
H2 O → H ∗ 2 + O
is a valid expression for the molecular weight of water (assuming that H and O are con-
stants defined as the molecular weight of hydrogen and oxygen respectively). This idea
can be carried further, e.g. the expansion
Ca (NO3 )2 (H2 O)4 → Ca + (N + O ∗ 3) ∗ 2 + (H ∗ 2 + O) ∗ 4
is a valid expression for the molecular weight of calcium nitrate. The whole idea is
to identify tokens in the formula and insert arithmetic operators when required. In the
simple examples above we have to distinguish five tokens
0−9 a−z A−Z ) (
and two operators
+ ∗
In addition we must obey three rules which are specific to chemical formulas: Element
names contain at most one lower case letter, which cannot be the first letter in the name,
and empty parentheses are not allowed in the formula. The full operator table is shown
in Table 6.1. It tells you which operator to insert given a left and right operand. Parsing
e.g. the input string ’H2O’ from left to right yields the following sequence:
le f t=H,right=2 le f t=2,right=O
H2O → H ∗ 2O → H∗2+O
Note that the two operators + and ∗ are what we call binary operators, i.e. they are of the
form x ◦ y where x is the left operand and y is the right operand. Hence, it is sufficient to
analyse just two characters at a time!

T 6.1: Operator table for converting chemical formulas


into arithmetic expressions.

right 0−9 a−z A−Z ) (


left
0−9 none + + none +
a−z ∗ error + none +
A−Z ∗ none + none +
) ∗ error + none +
( + + none error none
29
30 6. STRING PARSING

§ 27 Write a function expr = mw from formula parser(formula) which returns a


valid arithmetic expression from a given input string (chemical formula). E.g. the
function call expr = mw from formula parser(’H2O’) shall return the string expr =
’H*2+O’. Make use of the function op = mw binop(x,y) in your code.

C  . No big surprises here, except that I for some reason
(don’t remember exactly why) implemented the parser as RL and not LR. Anyway, the
Matlab code is nice and clean (Appendix C.29). 

§ 28 Write a function op = mw binop(x,y) that analyses the two operands x (left)


and y (right) and returns the correct operator from Table 6.1 (as a string).

C   . There are many ways to implement this operator
table and the one shown in Appendix C.30 is definitely not the most compact. However,
legibility is also an important issue! 
In the next exercise you will benefit from knowing the function [s,b] = get formula
vector(s, b, e, f). This function takes an input string s, a vector of stoichiometric factors b
which accompanies the list of known element symbols e, and an external multiplicative
factor f . The function syntax you should use is get formula vector(s, zeros(length(n),
1), e, 1.0). It will parse s from right to left and try to resolve the stoichiometric factors
corresponding to the supplied list of element symbols. The parsing continues till a right
paranthesis is found, or till the string is exhausted. If a right paranthesis is found get
formula vector calls itself recursively till the string s is exhausted, so in your case s shall
allways be an empty string on output.

§ 29 Write a function [A,e] = make formula matrix(formula1,formula2,. . .) that


analyses an arbitrary number of chemical formulas and calculates the coresponding
formula matrix A, and a list of chemical symbols e representing the rows of A.

F . I have elaborated the interface a little in Appendix C.31 to make
the function more flexible, but the biggest job was to get the chemical symbols correct
(it turned out that the chemical symbol of Lawrencium had changed from Lw to Lr since
the time I was a student). 

§ 30 Last but not least, try to program the function [s,b] = get formula vector(s,
b, e, f) as it was introduced above.

F . This is a fairly big programming job where you will need recursive
programming and ASCII-encoding. To make the code more versatile I have in Appendix
C.32 opened up for decimal numbers in the chemical formula. E.g. ’FeO0.977’ is a legal
input string. 

2. Cool stuff (regular expressions)


Consider the situation where you have a huge amount of information with some
(known) structure but are only interested in a small part of the data. Typically you may
be interested in extracting information from an HTML file (garbage filtering) or to sum-
marise the output from a big simulation run into a small table in Excel (report generation).
2. COOL STUFF (REGULAR EXPRESSIONS) 31

In order to retain the data of interest, regular expressions are very powerful. Table 6.2
shows a list of the most common expressions.

T 6.2: The most common regular


expressions

Symbol Meaning
ˆ Start of string
$ end of string
. any character
\ quote next character
∗ match zero or more
+ match one or more
? match zero or one
[] match set of characters
[ˆ] exclude set of characters
() group subexpression
\w match word [a-z A-Z0-9]
\W not a word [ˆa-z A-Z0-9]
\d match digit [0-9]
\D not a digit [ˆ0-9]
\s match white space
\S not a white space
| logical “or”

Assume we want to count the number of sentences in a text document. This can be
done using the regular expression [A-Z][ˆ.|ˆ!|ˆ?]+[.|!|?] on a string representation of the
document. The search will match everything which starts with a capital letter and ends
with . or ! or ? The end of the matching sub-string is used to define the start of the next
search till the entire string is fully explored.

§ 31 Calculate the CO2 equivalents for the vapor streams V1, V2 and V3 re-
ported in the data file HYSYS report.txt. The report format is shown in Appendix
E.4. Note that the HYSYS file contains much more data than what is needed to
solve the task. Regular expressions are useful to do the filtering job, but the Matlab
implementation of RE is rather ackward. It would of course be smarter to filter the
data in another language with gives a better support for RE, but we shall stick to
Matlab here because “to know a language you must learn about its limits”.

G  . First, the vapour streams in the output file from HYSYS
must be located. It is then possible to filter out the stream data needed and calculate
the CO2 equivalents. But, as you can see from Appendix C.33 the code is quite involved.
The job is still worth the efforts if there are lots of data to be processed. Ideally, however,
you should consider a language which is better suited for string handling and regular ex-
pressions like Ruby or Python. They yield less code which at the same time is easier to
write and maintain, see Appendix D.1 for an implementation in Ruby. 
APPENDIX A

Language elements

T A.1: File functions.

fopen open file


fclose close file

T A.2: Special variables of mathe-


matical character.

eps machine precision ε


ans last calculated result −
pi pi π
inf infinity ∞
NaN Not-a-Number −

T A.3: Special characters.

% comment (rest of line is ignored)


. . . statement continues on next line

T A.4: Basic commands that makes life easier, but


has little to do with programming.

pwd print working directory


whos list all variables in the work space
what list all functions in the local directory
disp display text on screen
exit exit the Matlab session
help give help topics
load read table from file
save save table to file
format change output format
cd change local directory

33
34 A. LANGUAGE ELEMENTS

T A.5: Program flow control instructions.

if;elseif;else;end declare conditional execution block(s)


while;end repeat execution block while logical argument is true
for start:step:stop; end repeat statements a specific number of times
break break innermost execution block
return break function execution
pause suspend execution
persistent save variables in local namespace
function declare function
feval evaluate functional
keyboard halt execution while reading from keyboard

T A.6: Instantiation operators. Used when shaping or filling a ma-


trix, a vector, etc.

[] vector (matrix) constructor


, row separator
; column separator
= assignment operator

vector or matrix transposition
end last row or column element
find evaluate logical argument for all vector/matrix elements

T A.7: Plotting commands.

loglog logarithmic plot


title graph title
ylabel y-axis label
xlabel x-axis label
axis control axes ranges
plot linear plot
hold hold current graph for additional plotting
grid add grid lines
legend place graph legends on the current plot

T A.8: Relational operators (logical operations).

eq;ne;gt;lt;ge;le numerical test operators =, , >, <, ≥, ≤


and;or;not logical (boolean) test operators ∨, ∧, ¬
any equivalent to sum(arg > 0) > 0 ∃
all equivalent to prod(arg > 0) > 0 ∀
isnan true if argument is NaN −
isinf true if argument is ∞ −
isempty true if empty array
iscell true if cell array
sort sort in ascending order
A. LANGUAGE ELEMENTS 35

T A.9: Algebraic operators.

+; − vector or matrix addition (subtraction)


∗ vector or matrix multiplication
/ right matrix division (dangerous)
\ left matrix division (dangerous)
.∗ element-by-element product
./ element-by-element division
.ˆ element-by-element exponentiation

T A.10: Set functions.

mod modulus division


max column maxium
min column minimum
round round towards nearest integer
floor round towards −∞
ceil round towards +∞
abs absolute value
rand random (uniform distribution) number

T A.11: Transcendental functions.

exp exponentiation
log natural logarithm
sin sine
cos cosine
sqrt square root

T A.12: String functions.

char create character array (string)


num2str convert number to string
strcat catenation
strcmp compare strings
upper convert to upper case
lower convert to lower case
strtok find token in string
findstr find substring in string
36 A. LANGUAGE ELEMENTS

T A.13: Linear algebra functions.

eye identity matrix


diag diagonal matrix
size vector/matrix dimension
linspace vector of equidistant points
logspace vector of logarithmic equidistant points
ones vector/matrix filled with 1’s
zeros vector/matrix filled with 0’s
reshape reshape vector/matrix
sum column sum of vector/matrix
prod column product of vector/matric

T A.14: Advanced linear algebra functions.

inv matrix inversion


lu LU-factorization
qr QR-factorization
rref matrix on row reduced echelon form
norm vector norm
eig matrix eigenvalues
rank matrix rank

T A.15: Functionals i.e. functions that take other functions as


arguments and produce a number.

fzero solve non-linear functions


quad Simpson integration
ode45 4’th order Runge-Kutta integration
rbvp4c 4’th order boundary value integration
optimset optimization data structure
fsolve nonlinear solver using the method of least squares
APPENDIX B

Examples

In Matlab a command can be entered at the system prompt without any left assigment.
It will then return the numerical value of the operation in the default variable ans (so there
is an assigment after all). Some trivial examples follow:

>> mod(6, 4)
ans = 2
>> floor(3.95)
ans = 3
>> ceil(3.95)
ans = 4
>> isempty([])
ans = 1
>> char([ a , b ,  c ])
ans = abc
>> num2str([1, 2, 3])
ans = 1 2 3
>> sort([2, 1, −4, 0])
ans = −4 0 1 2

Matrix inversion is simple in Matlab, but note that direct inversion is not much used —
there are more efficient ways to solve a system of linear equations:

A = inv([2, 1; 1, 2])
 
0.6667 −0.3333
A=
−0.3333 0.6667

LU-factorization is typically used in the first stage of a solution. It holds the outcome of
an ordinary Gauss elimination of the rows of the matrix:

[A, B] = lu([2, 1; 1, 2])


 
1.0000 0.0000
A=
0.5000 1.0000
 
2.0000 1.0000
B=
0.0000 1.5000
37
38 B. EXAMPLES

QR-factorization is similar to LU but has some nice additional properties (orthogonal


Q-matrix):
[A, B] = qr([2, 1; 1, 2])
 
−0.8944 −0.4472
A=
−0.4472 0.8944
 
−2.2361 −1.7889
B=
0.0000 1.3416
The row reduced echelon (staircase) form of a matrix properly identifies linear depen-
dencies:
[A, B] = rref([2, 1; 1, 2])
 
1.0000 0.0000
A=
0.0000 1.0000
 
B= 1 2
The 2-norm is a measure for the Euclidian length of a vector. It is defined as the square
root of the inner product of the vector with itself:
a = norm ([3, 4])
a=5
Matrix eigenvalues and eigenvectors are important in the stability analyses in process
control, differential equation solving and thermodynamic equilibrium theory:
[A, B] = eig([2, 1; 1, 2])
 
−0.7071 0.7071
A=
0.7071 0.7071
 
1.0000 0.0000
B=
0.0000 3.0000
The matrix rank is important for the solvability of an equation system. Matrices with full
ranks yield unique solutions while rank deficient matrices do not:
a = rank ([2, 1; 1, 2])
a=2
APPENDIX C

Matlab code

1. randolph
Randolph is a simple, yet effective random number generator for internal uses in this
course. The rand function in Matlab yields far better randomness, but is more difficult
to control by simple means (it used to be, but MathWorks has changed it — grrrr). With
emphrandolph you can set the initial state of the generator by simply issuing the com-
mand randolph(n), where n ≥ 1 is a random number (called the seed) of your choice.
The seed is much like a password, you must remember it in order to reproduce your cal-
culations! After randolph has been initialized you can issue the command randolph(n,m)
to generate n × m matrices of random numbers.
%The program implements a lagged Fibonacci pseudo-random number generator
%using subtraction [0]. A sequence of random numbers X(n) is obtained from
%the formula:
%
% X(i) = X(i-q) - X(i-p) mod M
%
%where M is 1 if the X’s are taken to be floating point reals in [0,1) as
%they are here. The period of this generator is (2ˆp-1)*2ˆ(b-1),where p is
%the largest lag and b is the number of significant bits in the numbers
%X(n).The lag needs to be chosen large enough to give a period much longer
%than the number of random numbers to be generated.Only certain lags (p,q)
%will give the maximal period of the generator [4, 5]. Some of these are
%listed below:
%
% p q
% 9689 4187
% 4423 2098
% 2281 1029
% 1279 418
% 607 273
% 521 168
% 250 103
% 127 63
% 97 33
% 55 24
% 31 13
% 17 5
%
%Small lags can cause problems with this generator [1, 2, 5]. Larger lags
%give larger periods and empirically seem to give "better" random numbers
%[2, 4, 5]). I recommend using at least (1279,418),and ideally much larger
%lags such as (9689,4187). Larger lags give higher quality random numbers
%and longer period, with the only tradeoff being increased memory use and
%initialization time. However initialization is very fast, and the memory
39
40 C. MATLAB CODE

%used is only of order p words, so p=2281 will add less than 10 Kbytes to
%the memory required for the user program. This generator performs well in
%empirical statistical tests [2, 4] as long as a large lag is used. This
%does not necessarily mean it will perform well for your application.It is
%recommended that you check your results by also running your program
%using another good random number generator (see [1] for recommendations).
%
%0. http://www.npac.syr.edu/projects/random/generators/fibadd/fibadd.html
%1. P. D. Coddington, Random number generators for parallel computers,
% NHSE Review, Volume 2, 1996.
%2. P. D. Coddington, Analysis of Random Number Generators Using Monte
% Carlo Simulation, Int. J. Mod. Phys. C 5, 547 (1994). NPAC technical
% report SCCS-526.
%3. F. James, A Review of Pseudo-random Number Generators,
% Comput.Phys.Comm. 60, 329 (1990).
%4. D. E. Knuth, The Art of Computer Programming Vol. 2: Seminumerical
% Methods, Addison-Wesley, Reading, Mass., 1981.
%5. G. A. Marsaglia, A current view of random number generators, in
% Computational Science and Statistics: The Interface,
% ed. L. Balliard, Elsevier, Amsterdam, 1985.

function [x] = randolph(n,m)

persistent x0 o p q;

if (nargin==1)
if (n<1)
disp(’Your seed number must be >= 1, try again!’);
return;
end
x0 = [0.52189398762154 0.22586125989448 0.78962235300517 ...
0.73889796980862 0.61383531911974 0.13010525023880 ...
0.64626222776828 0.22126297192155 0.92287218663571 ...
0.58354708643659 0.36750946939959 0.31286745921603 ...
0.59021783397155 0.05315767833273 0.37021959254501 ...
0.88726820502120 0.97633988457881 0.76793407983075 ...
0.24525730723827 0.91975917519955];
x0 = x0*n; % start modifying the seed vector
x0 = x0 - floor(x0); % calculate the new seed
o = max(size(x0)); % dim(x0)
p = 17; % 1st random parameter. Note that dim(x0) >= p
q = 5; % 2nd random parameter

else
if (isempty(x0))
disp(’You must initialize first, use randolph(n) where n>=1’);
return;
end
x = [x0,zeros(1,n*m)]; % initialize random vector
for i=1:n*m % repeat for all elements
x(o+i) = x(o+i-p) - x(o+i-q); % Fibonacci sequence
x(o+i) = x(o+i) - floor(x(o+i)); % Calculate random numbers
end
2. OCTANE 41

x0 = x(end-o+1:end); % update the seed vector


x = reshape(x(o+1:end),n,m); % reshape to requested format
end

2. octane
clear;
format short;

prompt = input(’Normal or bad case? [n/b]: ’,’s’);

if (strcmp(prompt,’b’))
A = [90 105 95; 1-1e-15 1 1; 1 1 1];
disp(’Bad coefficient matrix:’)
else
A = [90 105 95; 0.2 2 0.5; 1 1 1];
disp(’Normal coefficient matrix:’)
end
disp(A);
pause;

b = [98; 1; 1];
disp(’Right hand side vector (specifications):’)
disp(b);
pause;

x = zeros(size(b));
B = [A,b];
disp(’Adjoint matrix:’)
disp(B);
pause;

B(2,:) = B(2,:) - (B(2,1)/B(1,1))*B(1,:);


disp(’Element 2,1 eliminated:’)
disp(B);
pause;

B(3,:) = B(3,:) - (B(3,1)/B(1,1))*B(1,:);


disp(’Element 3,1 eliminated:’);
disp(B);
pause;

B(3,:) = B(3,:) - (B(3,2)/B(2,2))*B(2,:);


disp(’Element 3,2 eliminated:’)
disp(B);
pause;

x(3) = B(3,4)/B(3,3);
disp(’Solution variable 3:’)
disp(x(3));
pause;

x(2) = (B(2,4)-B(2,3)*x(3))/B(2,2);
disp(’Solution variable 2:’)
42 C. MATLAB CODE

disp(x(2));
pause;

x(1) = (B(1,4)-B(1,3)*x(3)-B(1,2)*x(2))/B(1,1);
disp(’Solution variable 1:’)
disp(x(1));
pause;

format long e;
disp(’The solution vector compared to Matlab:’)
disp([x,inv(A)*b]);
pause;

disp(’Back calculated results compared to Matlab:’)


disp([A*x,A*(inv(A)*b)]);

3. figure 2 8
clear;

I = eye(2,2);
O = zeros(2,2);
a = [2 , 1];
s1 = [99, -1];
s2 = [10,-90];
o = O(1,:);
e = I(1,:);

b = [101; 0; 2; 0; 0; o’; 0; o’];

A = [I, O, O, O , O ; ... % specification of stream 1


o, o, o, o , e ; ... % specification of A in stream 5
o, o, o, o , s1; ... % specification of top product
o, o, o, s2, o ; ... % specification of bottom product
I,-I, O, I , O ; ... % component balance (mixer)
o, a,-a, o , o ; ... % atom balance (reactor)
O, O, I,-I ,-I ]; % component balance (separator)

[B,j] = rref([A,b]); % stair case (exchelon form)


xp = zeros(size(b)); % initialize
xp(j) = B(1:length(j),end); % particular solution
xh = null(A); % homogenous solution

n = 200; % number of plot points


X = xp*ones(1,n) - xh*linspace(0,2000,n); % n solution vectors

s3 = [5,6]; % stream 3
s4 = [7,8]; % stream 4
n3 = sum(X(s3,:),1); % total flow of stream 3
n4 = sum(X(s4,:),1); % total flow of stream 4
Q = X(s3(2),:).ˆ2./(X(s3(1),:).*n3); % equilibrium quotient

loglog(n4,Q,’r’);
5. FERTILIZER BALANCE 43

title(’Equilibrium restricted reaction’)


ylabel(’x_{B}ˆ{2}/x_{A}’)
xlabel(’Resirculation flow [mol sˆ{-1}]’)
axis([10 1000 0.05 10]);
hold on;
grid;

K = 0.74; % equilibrium constant


i = find(Q<K); % possible states

loglog(n4(i),Q(i),’g’);
legend(’Q>K’,’Q<K’);
hold off;

disp(round(xp-1568.44*xh));

4. partialinv
%Purpose : Solve the partial inversion problem Ax = b where some of the
% elements in b are unknown, while an equal number of elements in
% x are known (a total of rank(A) elements in x and b must be
% known all over)
%Author : Tore Haug-Warberg
%Date : October 16 1999
%Syntax : [x,b] = partialinv(A,x,b)
%Input : A = coefficient matrix
% x = left hand side vector
% b = right hand side vector
%Output : x = updated left hand side vector
% b = updated right hand side vector
%External: eye inv isnan not size

function [x,b] = partialinv(A,x,b)

i = isnan(x);
j = isnan(b);
I = eye(size(A));
c = inv([I(not(i),:);A(not(j),:)])*[x(not(i));b(not(j))];
x(i) = I(i,:)*c;
b(j) = A(j,:)*c;

5. fertilizer balance
clear;

% Reactant formula matrix (in)


% NH3 O2 Ca3(Po4)2 CaCO3 H2O CO2
A = [1 0 0 0 0 0; ... % N
3 0 0 0 2 0; ... % H
0 2 8 3 1 2; ... % O
0 0 0 1 0 1; ... % C
0 0 3 1 0 0; ... % Ca
44 C. MATLAB CODE

0 0 2 0 0 0]; ... % P

NH3 = 1; % column number in A belonging to NH3


O2_in = 2; % column number in A belonging to O2
phosphate = 3; % column number in A belonging to Ca3(PO4)2
calcite = 4; % column number in A belonging to CaCO3
H2O_in = 5; % column number in A belonging to H2O
CO2_in = 6; % column number in A belonging to CO2

% Product formula matrix (out)


% CN MAP CO2 AN O2 H2O
B = [2 1 0 2 0 0; ... % N
8 6 0 4 0 2; ... % H
10 4 2 3 2 1; ... % O
0 0 1 0 0 0; ... % C
1 0 0 0 0 0; ... % Ca
0 1 0 0 0 0]; ... % P

CN = 1; % column number in B belonging to Ca(NO3)2


MAP = 2; % column number in B belonging to NH4H2PO4
CO2_out = 3; % column number in B belonging to CO2
AN = 4; % column number in B belonging to NH4NO3
O2_out = 5; % column number in B belonging to O2
H2O_out = 6; % column number in B belonging to H2O

%Molecular weights
w = [14.0067 1.00797 15.9994 12.01115 40.08, 30.9738]; % atoms
wa = w*A; % reactants
wb = w*B; % products

x = zeros(size(wa))’;
y = zeros(size(wb))’;

x(NH3) = 1300/wa(NH3); % NH3 capacity is 1300 ton/day


x(O2_in) = NaN; % unknown O2 consumption
x(phosphate) = NaN; % unknown phosphate consumption
x(calcite) = NaN; % minimize calcite input
x(H2O_in) = 100/wa(H2O_in); % minimize H2O input
x(CO2_in) = 0; % minimize CO2 input

y(CN) = 1000/wb(CN); % 1600 ton/day CN production


y(MAP) = 200/wb(MAP); % MAP capacity is 500 ton/day
y(CO2_out) = NaN; % unknown CO2 production
y(AN) = NaN; % unknown AN production
y(O2_out) = 0; % zero O2 production
y(H2O_out) = NaN; % unknown H2O production

[x,y] = partialinv(inv(B)*A,x,y); % solve the mole balance

disp(’Case I’); % show title


disp([diag(wa)*x,diag(wb)*y]); % show mass flows in ton/day

x(NH3) = 1300/wa(NH3); % NH3 capacity is 1300 ton/day


6. ACID BASE REACTION MATRIX 45

x(O2_in) = NaN; % unknown O2 consumption


x(phosphate) = NaN; % unknown phosphate consumption
x(calcite) = 0; % minimize calcite input
x(H2O_in) = 0; % minimize H2O input
x(CO2_in) = 0; % minimize CO2 input

y(CN) = NaN; % unknown CN production


y(MAP) = 200/wb(MAP); % MAP capacity is 500 ton/day
y(CO2_out) = NaN; % unknown CO2 production
y(AN) = NaN; % unknown AN production
y(O2_out) = 0; % zero O2 production
y(H2O_out) = NaN; % unknown H2O production

[x,y] = partialinv(inv(B)*A,x,y); % solve the mole balance

disp(’Case II’); % show title


disp([diag(wa)*x,diag(wb)*y]); % show mass flows in ton/day

6. acid base reaction matrix


clear;
format short;
format compact;

%Let’s first put up the formula matrix (identical to the atom matrix if
%the B, H, A, OH symbols are interpreted differently).

% B BH+ HA A- H2O OH- H+


A = [1 1 0 0 0 0 0; ... % B
0 1 1 0 1 0 1; ... % H
0 0 1 1 0 0 0; ... % A
0 0 0 0 1 1 0]; % OH

name = {’B’,’BH+’,’HA’,’A-’,’H2O’,’OH-’,’H+ ’}’;

disp(’Formula matrix:’)
disp(A);
pause;

A(1,:) = A(1,:) - (A(1,2)/A(2,2))*A(2,:);


disp(’Element 1,2 eliminated:’)
disp(A);
pause;

A(1,:) = A(1,:) - (A(1,3)/A(3,3))*A(3,:);


disp(’Element 1,3 eliminated:’)
disp(A);
pause;

A(2,:) = A(2,:) - (A(2,3)/A(3,3))*A(3,:);


disp(’Element 2,3 eliminated:’)
disp(A);
pause;
46 C. MATLAB CODE

A(1,:) = A(1,:) - (A(1,5)/A(4,5))*A(4,:);


disp(’Element 1,5 eliminated:’)
disp(A);
pause;

A(2,:) = A(2,:) - (A(2,5)/A(4,5))*A(4,:);


disp(’Element 2,5 eliminated:’)
disp(A);
pause;

tmp = A(:,5);
A(:,5) = A(:,4);
A(:,4) = tmp;
tmp = name{5};
name{5}= name{4};
name{4}= tmp;
disp([’Swap components ’,name{4},’ and ’,name{5}])
disp(A);
pause;

N(:,1) = [A(:,5);-1;0;0];
disp(’First set of reaction coefficients:’)
disp([char(name),abs(zeros(length(name),3)),num2str(N)]);
pause;

N(:,2) = [A(:,6);0;-1;0];
disp(’Second set of reaction coefficients:’)
disp([char(name),abs(zeros(length(name),3)),num2str(N)]);
pause;

N(:,3) = [A(:,7);0;0;-1];
disp(’Third set of reaction coefficients:’)
disp([char(name),abs(zeros(length(name),3)),num2str(N)]);
pause;

N(:,2) = -N(:,2);
N(:,1) = -N(:,1);
disp(’Change direction of reaction 1 and 2:’)
disp([char(name),abs(zeros(length(name),3)),num2str(N)]);

7. water viscosity 1bar fit


clear;

K2C = 273.15;

load -ascii ..\data\water_viscosity_1bar_data.txt

t = water_viscosity_1bar_data(:,1) + K2C;% experimental temperatures


visc = water_viscosity_1bar_data(:,3); % experimental viscosities
e = ones(size(t)); % unity vector
[t,i] = sort(t); % sort in ascending order
visc = visc(i); % re-order viscosities as well
A = [e e./t e./(t.ˆ2)]; % coefficient matrix
8. WATER VAPOR PRESSURE FIT 47

c = inv(A’*A)*A’*log(visc); % least square solution

%Generate (overwrite) the viscosity function "on the fly"


ans = input(’Overwrite old ’’water_viscosity_1bar.m’’ y/n [n]: ’,’s’);
if ans==’y’
out = 0;
func = ’water_viscosity_1bar’;
mfil = [func,’.m’];
format = ’%s\r\n’;
fid = fopen(mfil,’w’);
out = out + fprintf(fid,format, ...
[’%Viscosity of water calculated from ’, ...
’log(visc)=c(1)+c(2)/T+c(3)/Tˆ2’]);
out = out + fprintf(fid,format, ...
’%Viscosity in [kg/m*s], temperature in [K].’);
out = out + fprintf(fid,format, ...
[’ function [visc] = ’,func,’(t);’]);
out = out + fprintf(fid,format, ...
[’ c = [’,num2str(c’,’%15.11g’),’];’]);
out = out + fprintf(fid,format, ’ e = ones(size(t));’);
out = out + fprintf(fid,format, ...
’ visc = exp(c(1)*e+c(2)*e./t+c(3)*e./(t.ˆ2));’);
fclose(fid);
disp([num2str(out),’ bytes of code written to ’,mfil]);
end

%Show results from parameter fitting


plot(t-K2C,visc,’*’,t-K2C,exp(A*c));
title(’Viscosity of water at 1 bar’);
xlabel(’Temperature [C]’);
ylabel(’Viscosity [kg/m*s]’);
grid;

8. water vapor pressure fit


clear;

load -ascii ..\data\water_vapor_pressure_data.txt; % load ASCII-file

%Define critical constants and fit experimental data to Wagner’s equation


tc = 647.1; % critical temperature [K]
pc = 220.64e5; % critical pressure [Pa]
t = water_vapor_pressure_data(:,1); % observed temperatures [K]
p = water_vapor_pressure_data(:,2)*1e6; % observed pressures [Pa]
[t,i] = sort(t); % temperatures in increasing order
p = p(i); % rearrange p in the same order
i = find(t>tc); % find temperatures outside range
t(i) = []; % remove them (avoid trouble)
p(i) = []; % rearrange p in the same order
e = ones(size(t)); % unity vector
tr = t/tc; % reduced temperature
pr = p/pc; % reduced pressure
A = [e-tr,(e-tr).ˆ1.5,(1-tr).ˆ3,(e-tr).ˆ6]; % coefficient matrix
b = tr.*log(pr); % right hand side
48 C. MATLAB CODE

%c = inv(A’*A)*A’*b; % solve normal equations


[Q,R] = qr(A); % QR-decomposition
c = inv(R’*R)*A’*b; % more stable solution

%Generate (overwrite) the vapor pressure function "on the fly"


ans = input(’Overwrite old ’’water_vapor_pressure.m’’ y/n [n]: ’,’s’);
if ans==’y’
out = 0;
func = ’water_vapor_pressure’;
mfil = [func,’.m’];
format = ’%s\r\n’;
fid = fopen(mfil,’w’);
out = out + fprintf(fid,format,[’%Vapor pressure of water’, ...
’ using Wagner’’s equation.’]);
out = out + fprintf(fid,format,[’%Pressure in [Pa],’, ...
’ temperature in [K].’]);
out = out + fprintf(fid,format,[’ function [lnp] = ’,func,’(t);’]);
out = out + fprintf(fid,format,[’ tc = ’,num2str(tc),’;’]);
out = out + fprintf(fid,format,[’ pc = ’,num2str(pc),’;’]);
out = out + fprintf(fid,format,[’ c = [’,num2str(c’,’%15.11f’),’];’]);
out = out + fprintf(fid,format, ’ e = ones(size(t));’);
out = out + fprintf(fid,format, ’ tr = t/tc;’);
out = out + fprintf(fid,format,[’ tmp = c(1)*(e-tr) + c(2)*(e-tr).ˆ1.5’,...
’ + c(3)*(e-tr).ˆ3 + c(4)*(e-tr).ˆ6;’]);
out = out + fprintf(fid,format, ’ lnp = tmp./tr + log(pc)*e;’);
fclose(fid);
disp([num2str(out),’ bytes of code written to ’,mfil]);
end

%The experimental data span the entire range from the triple point to the
%critical point, which means it will be quite pointless to show the fit in
%an ordinary 1/T,lnP-plot. The data are therefore transformed into the
%deviation plot 1/T,dlnP, where dlnp = log(p) - [a + b(1/Tmin-1/T)], and
%a = log(Pmin), and b = (log(Pmax)-log(Pmin))/(1/Tmin-1/Tmax).

tmin = min(t); % mininum temperature


tmax = max(t); % maximum temperature
lnpmin = min(log(pr)); % minimum log(reduced pressure)
lnpmax = max(log(pr)); % maximum log(reduced pressure)
a = lnpmin; % 1 parameter in linearized plot
b = (lnpmax-lnpmin)/(1/tmin-1/tmax);% 2 parameter in linearized plot
lnplin = a*e + b*(e/tmin-e./t); % linearized 1/T,lnP-plot
dpobs = log(pr) - lnplin; % observed deviations
dtnorm = (e./t - e/tmin)/(1/tmax-1/tmin); % normalized 1/T data
dpcalc = (A*c)./tr - lnplin; % calculated pressure devations

plot(dtnorm,dpobs,’o’,dtnorm,dpcalc);
title(’Vapor pressure of water (Wagner’’s equation)’)
xlabel(’Normalized 1/T (from triple to critical point)’)
ylabel(’Transformed log(p) - [a+b(1/Tmin-1/T)]’)
grid;
pause;
9. WATER DENSITY 1BAR FIT 49

plot(t,exp((A*c)./tr)./pr-e);
title(’Vapor pressure of water (Wagner’’s equation)’)
xlabel(’Temperature [K] (from triple to critical point)’)
ylabel(’Relative pressure deviation’)
grid;

9. water density 1bar fit


clear;

%Maximum density of air-free water is approx. 999.97490+/-0.0001 kg mˆ{-3}


%at 3.98 degree Celsius. Interpolated from Takenaka,M.,Masui,R.Metrologia,
%27, 165-171, (1990).
K2C = 273.15;
dmax = 999.97490;
tmax = K2C + 3.98;

load -ascii ..\data\water_density_1bar_data.txt

t = water_density_1bar_data(:,1); % experimental temperatures


d = water_density_1bar_data(:,3); % experimental densities
e = ones(size(t)); % unity vector
[t,i] = sort(t); % sort in ascending order
d = d(i); % re-order the densities as well
dt = t - tmax*e; % make sure max. temperature is right
A = [abs(dt).ˆ1.3,abs(dt).ˆ1.6]; % coefficient matrix
c = inv(A’*A)*A’*log(d/dmax); % least square solution

%Generate (overwrite) the density function "on the fly"


ans = input(’Overwrite old ’’water_density_1bar.m’’ y/n [n]: ’,’s’);
if ans==’y’
out = 0;
func = ’water_density_1bar’;
mfil = [func,’.m’];
format = ’%s\r\n’;
fid = fopen(mfil,’w’);
out = out + fprintf(fid,format, ’%Density of water (1 bar) calculated’);
out = out + fprintf(fid,format, ’%from log(rho) = tauˆ1.3 + tauˆ1.6,’);
out = out + fprintf(fid,format, ’%where rho is d/dmax and tau is ’);
out = out + fprintf(fid,format, ’%t-tmax. Densities in [kg/mˆ3] and’);
out = out + fprintf(fid,format, ’%temperatures in [K].’);
out = out + fprintf(fid,format,[’ function [d] = ’,func,’(t);’]);
out = out + fprintf(fid,format,[’ c = [’,num2str(c’,’%15.11f’),’];’]);
out = out + fprintf(fid,format, ’ e = ones(size(t));’);
out = out + fprintf(fid,format,[’ tmax = ’,num2str(tmax,’%15.11f’),’;’]);
out = out + fprintf(fid,format,[’ dmax = ’,num2str(dmax,’%15.11f’),’;’]);
out = out + fprintf(fid,format, ’ dt = abs(t-tmax*e);’);
out = out + fprintf(fid,format, ’ d = dmax*exp(c(1)*dt.ˆ1.3+c(2)*dt.ˆ1.6);’);
fclose(fid);
disp([num2str(out),’ bytes of code written to ’,mfil]);
end

%The model looks quite OK in absolute terms


plot(t-K2C,d,’*’,t-K2C,dmax*exp(A*c));
50 C. MATLAB CODE

title(’Density of water at 1 bar’);


xlabel(’Temperature [C]’);
ylabel(’Density [kg/mˆ3]’);
pause;

%But the deviation plot shows oscillations (typical for heuristic models)
plot(t-K2C,d-dmax*exp(A*c),’o’);
title(’Residual density of water at 1 bar’);
xlabel(’Temperature [C]’);
ylabel(’Density [kg/mˆ3]’);
grid;

10. acid base titration curve


clear;

%Solve the titration problem B+HA = BH(+) + A(-) using direct substitution
%of variables to obtain a fourth order polynomial in n(H+), i.e the number
%of moles of protons at equilibrium.

k1 = 10ˆ(-4.76); % pKb NH3


%k1 = 10ˆ(-2.35); % pKb H2O2
%k1 = 10ˆ(+2.00); % pKb NaOH
k2 = 10ˆ(-4.76); % pKa CH3COOH
%k2 = 10ˆ(-3.74); % pKa HCOOH
%k2 = 10ˆ(+1.37); % pKa HNO3
k3 = 10ˆ(-14); % pKw

cb = 0.1; % molar concentration of base


ca = linspace(0,2*cb,1000)’; % moles of acid added
e = ones(size(ca)); % unity vector with same shape as n
ph = zeros(size(ca)); % negative log10(molar H+ concentration)

c = [-k1*e, ... % 4th order coefficient


k1*k2*e + k1*cb + k3, ... % 3rd order coefficient
k1*k2*ca + k1*k3 - k1*k2*cb - k2*k3, ... % 2nd order coefficient
-k2*k3*ca - k3*k3 - k1*k2*k3, ... % 1st order coefficient
k3*k3*k2*e]; % 0th order coefficient

%Solve fourth order polynomial repeatedly (i.e. all titration points)


for k=1:max(size(ca))
x = roots(c(k,:));
ph(k) =-log10(-max(x(find(x<0))));
end

plot(ca,ph);
title(’Titration curve for NH3 - CH3COOH’);
xlabel(’Acid added [mol]’);
ylabel(’pH’);
hold on;
grid;

%Find inflexion points (quite simple because the x-axis values are mono-
%tonic and equidistant)
12. PRESSURE DROP AT FIXED FLOW 51

curvature = diff(diff(ph)); % numerical second derivative


inflexion = find(curvature(1:end-1).*curvature(2:end)<0); % sign shift

plot(ca(inflexion) ,ph(inflexion) ,’or’); % plot lower limit


plot(ca(inflexion+1),ph(inflexion+1),’or’); % plot upper limit
hold off;

11. colebrook
function [r] = colebrook(lnf,lnRe,eod)
r = lnf/2 + log(-2*log10(eod/3.7+2.51./(exp(lnf/2).*exp(lnRe))));

12. pressure drop at fixed flow


T = 8 + 273.15; % temperature [K]
L = 2000; % pipe length [m]
Q = 0.5; % volumetric flow rate [m3/min]
D = 0.05; % pipe diameter [m]
eod = 1e-3; % relative pipe surface roughness (commercial steel)
mu = water_viscosity_1bar(T); % viscosity [kg/m*s]
rho = water_density_1bar(T); % density [kg/m3]
v = Q/(60*pi*(D/2)ˆ2); % flow velocity [m/s]
lnRe = log(rho*v*D) - log(mu); % log(Reynold number)

lnf = -5; % initial estimate log(Fanning friction)


opt = optimset(’Display’,’iter’); % display iteration progress

lnf = fzero(@colebrook,lnf,opt,lnRe,eod);

g = 9.80665; % standard acceleration of free fall [m/s2]


hs = exp(lnf)*L*vˆ2/(2*D*g); % m H2O at T [K]
dp = hs*rho*g/1e5; % bar

disp([’ ’]);
disp([’Case I’]);
disp([’Diameter : ’,num2str(D ,4),’ [m]’]);
disp([’Pressure drop : ’,num2str(hs,4), ...
’ [m H2O at ’,num2str(round(T-273.15)),’ C]’]);
disp([’Pressure drop : ’,num2str(dp,4),’ [bar]’]);
disp([’ ’]);
disp([’Press any key to continue’]);
pause;

D = 0.10; % new pipe diameter [m]


v = Q/(60*pi*(D/2)ˆ2); % new flow velocity [m/s]
lnRe = log(rho*v*D) - log(mu); % new log(Reynold) number

lnf = fzero(@colebrook,lnf,opt,lnRe,eod);

hs = exp(lnf)*L*vˆ2/(2*D*g); % m H2O at T [K]


dp = hs*rho*g/1e5; % bar

disp([’ ’]);
disp([’Case II’]);
52 C. MATLAB CODE

disp([’Diameter : ’,num2str(D ,4),’ [m]’]);


disp([’Pressure drop : ’,num2str(hs,4), ...
’ [m H2O at ’,num2str(round(T-273.15)),’ C]’]);
disp([’Pressure drop : ’,num2str(dp,4),’ [bar]’]);

13. friction and reynold


function [r] = friction_and_reynold(x,fun,s)

lnRe = x(:,1);
lnf = x(:,2);
r = zeros(size(x));

dp = s.dp;
D = s.D;
rho = s.rho;
L = s.L;
eod = s.eod;
mu = s.mu;

r(:,1) = log(2*dp.*rho.*D.ˆ3) - log(L.*mu.ˆ2) - lnf - 2*lnRe;


r(:,2) = feval(fun,lnf,lnRe,eod);

14. flow at fixed pressure drop


clear;

T = 8 + 273.15; % temperature [K]


s.L = 2000; % pipe length [m]
s.D = 0.05; % pipe diameter [m]
s.eod = 1e-3; % relative pipe surface roughness (commercial steel)
s.mu = water_viscosity_1bar(T); % viscosity [kg/m*s]
s.rho = water_density_1bar(T); % density [kg/m3]
s.dp = 3e5; % pressure drop [Pa]

opt = optimset(’Display’,’iter’); % display iteration progress

lnRe = 10; % initial estimate of log(Reynold number)


lnf = -8; % initial estimate of log(Fanning friction)

x = fsolve(@friction_and_reynold,[lnRe,lnf],opt,@colebrook,s);% solve
Q = 60*pi*exp(x(:,1)).*s.mu.*s.D./(4*s.rho); % flow rate [mˆ3/min]
f = exp(x(:,2)); % friction factor

disp([’ ’]);
disp([’Case I’]);
disp([’Diameter : ’,num2str(s.D ,4),’ [m]’]);
disp([’Pressure drop : ’,num2str(s.dp,4),’ [bar]’]);
disp([’Friction factor : ’,num2str(f ,4),’ [-]’]);
disp([’Flow rate : ’,num2str(Q ,4),’ [mˆ3/min]’]);
disp([’ ’]);
disp([’Press any key to continue’]);
pause;
16. COLEBROOK VS LAMINAR 53

s.D = 0.10; % new pipe diameter [m]

x = fsolve(@friction_and_reynold,[lnRe,lnf],opt,@colebrook,s); % solve
Q = 60*pi*exp(x(:,1)).*s.mu.*s.D./(4*s.rho); % flow rate [mˆ3/min]
f = exp(x(:,2)); % friction factor

disp([’ ’]);
disp([’Case II’]);
disp([’Diameter : ’,num2str(s.D ,4),’ [m]’]);
disp([’Pressure drop : ’,num2str(s.dp,4),’ [bar]’]);
disp([’Friction factor : ’,num2str(f ,4), ’[-]’]);
disp([’Flow rate : ’,num2str(Q ,4),’ [mˆ3/min]’]);

15. laminar
function [r] = laminar(lnf,lnRe,dummy)
r = lnf + lnRe - log(64);

16. colebrook vs laminar


clear;

n = 100; % number of plot points


T = 20 + 273.15; % temperature [K]

s.L = 2000; % pipe length [m]


s.D = logspace(-3,1,n)’; % pipe diameter [m]
s.eod = 1e-3; % relative pipe surface roughness (commercial steel)
s.mu = water_viscosity_1bar(T); % viscosity [kg/m*s]
s.rho = water_density_1bar(T); % density [kg/m3]
s.dp = 3e5; % pressure drop [Pa]

opt = optimset(’Display’,’iter’); % display iteration progress

lnRe = 10*ones(n,1); % initial estimate of log(Reynold number)


lnf = -8*ones(n,1); % initial estimate of log(Fanning friction)

x = fsolve(@friction_and_reynold,[lnRe,lnf],opt,@laminar,s); % solve
Rel = exp(x(:,1)); % laminar Reynold number
Ql = 60*pi*Rel.*s.mu.*s.D./(4*s.rho); % laminar flow rate [mˆ3/min]
fl = exp(x(:,2)); % laminar friction factor

x = fsolve(@friction_and_reynold,[lnRe,lnf],opt,@colebrook,s); % solve
Ret = exp(x(:,1)); % turbulent Reynold number
Qt = 60*pi*exp(x(:,1)).*s.mu.*s.D./(4*s.rho); % flow rate [mˆ3/min]
ft = exp(x(:,2)); % turbulent friction factor

loglog(s.D,Ql,’b’,s.D,Qt,’r’);
title(’Turbulent & laminar flow at constant \Delta P’);
xlabel(’Pipe diameter [m]’);
ylabel(’Flow rate [mˆ3/min]’);
legend(’Laminar’,’Turbulent’);
grid;
disp(’ ’)
54 C. MATLAB CODE

disp(’Press any key to continue’)


pause;

loglog(s.D,Rel,’b’,s.D,Ret,’r’)
title(’Turbulent & laminar Re at constant \Delta P’);
xlabel(’Pipe diameter [m]’);
ylabel(’Re’);
legend(’Laminar’,’Turbulent’);
grid;
pause;

loglog(Rel,fl,’b’,Ret,ft,’r’);
title(’Turbulent & laminar Fanning friction at constant \Delta P’);
xlabel(’Re’);
ylabel(’Friction factor f’);
legend(’Laminar’,’Turbulent’);
grid;
pause;

17. chon
%Calculates molecular weight of CHON-compounds.
function [mw] = chon(x,y,z,w)
mw = x*12.01115 + y*1.00797 + z*15.9994 + w*14.0067;

18. water viscosity 1bar


%Viscosity of water calculated from log(visc)=c(1)+c(2)/T+c(3)/Tˆ2
%Viscosity in [kg/m*s], temperature in [K].
function [visc] = water_viscosity_1bar(t);
c = [-8.0003593134 -1470.7557834 526396.01377];
e = ones(size(t));
visc = exp(c(1)*e+c(2)*e./t+c(3)*e./(t.ˆ2));

19. water vapor pressure


%Vapor pressure of water using Wagner’s equation.
%Pressure in [Pa], temperature in [K].
function [lnp] = water_vapor_pressure(t);
tc = 647.1;
pc = 22064000;
c = [-7.78664494819 1.50070473755 -2.82073715777 -1.20214640864];
e = ones(size(t));
tr = t/tc;
tmp = c(1)*(e-tr) + c(2)*(e-tr).ˆ1.5 + c(3)*(e-tr).ˆ3 + c(4)*(e-tr).ˆ6;
lnp = tmp./tr + log(pc)*e;

20. water density 1bar


%Density of water (1 bar) calculated
%from log(rho) = tauˆ1.3 + tauˆ1.6,
%where rho is d/dmax and tau is
%t-tmax. Densities in [kg/mˆ3] and
%temperatures in [K].
function [d] = water_density_1bar(t);
c = [0.00003932621 -0.00003868077];
22. DIFFUSION 55

e = ones(size(t));
tmax = 277.13000000000;
dmax = 999.97490000000;
dt = abs(t-tmax*e);
d = dmax*exp(c(1)*dt.ˆ1.3+c(2)*dt.ˆ1.6);

21. rachford rice


%Purpose : Rachford-Rice 2-phase flash calculation
%Author : Tore Haug-Warberg
%Date : March 14 1993
%Syntax : [x,y,l] = rachford_rice(z,k)
%Input : z = feed mole fractions vector
% k = K-value vector
%Output : x = liquid mole fraction vector
% y = vapor mole fraction vector
% l = Liquid fraction
%External: abs length min ones sum

function [x,y,l] = rachford_rice(z,k)

%Initializations
tol = 1.e-6; %Convergence tolerance
e = ones(length(k),1); %Unity vector
l = 0.5; %Initial estimate of liquid fraction
dl = 1.0; %Liquid fraction increment
z = z/sum(z); %Normalize feed composition

%Verifications
if length(z)˜= length(k); return; end
if min (z) < 0.0 ; return; end
if min (k) < 0.0 ; return; end
if min (k) > 1.0 ; l=0.0; x=0.0*z; y=z; return; end
if max (k) < 1.0 ; l=1.0; y=0.0*z; x=z; return; end

%Rachford-Rice iteration
while abs(dl) > tol
f = e’*((z.*(e-k))./(l*e+(1-l)*k));
dfdl = -e’*((z.*(e-k).ˆ2)./((l*e+(1-l)*k).ˆ2));
dl = -f/dfdl;
l = l + dl;
end

x = z./(l*e+(1-l)*k);
y = k.*x;

if l > 1.0; l=1.0; x=z; y=0.0*e; end


if l < 0.0; l=0.0; y=z; x=0.0*e; end

return

22. diffusion
function dummy
56 C. MATLAB CODE

clear all
close all

% Solution of the differential equation with no reaction on the surface D


zeta = [0 1]; % Starting value for zeta

% The starting values of gamma is chosen to satisfy the boundary conditio-


% ns given for the problem. Here with a better starting value, the numeri-
% cal solution could be closer to the analytical.

gamma = [1 -0.26]; % Starting value for gamma and its derivative


[a,b] = ode23(@equations,zeta,gamma); % Solving the differential equation

plot(a,b(:,1),’:’)
hold on

% Solution of the differential equation with reaction on the surface D


zeta = [0 1]; % starting value for zeta
gamma = [1 -1.1]; % Starting value for gamma and its derivative
[a,b] = ode23(@equations,zeta,gamma); %solving the differential equation

plot(a,b(:,1),’-.’)

% To compare the numeric solution with the analytical the analytical solu-
% tion is found
zetad = [0:.001:1];
kodab = 0.25;
l = 1;
th = sqrt(kodab*lˆ2);

% Analytical solution with no reaction on surface D


g1 = (cosh(th).*cosh(th.*zetad) - sinh(th).*sinh(th.*zetad))./cosh(th);

plot(zetad,g1,’-.g’)

% Analytical solution with reaction on surface D


g2 = (sinh(th).*cosh(th.*zetad)-cosh(th).*sinh(th.*zetad))./sinh(th);

plot(zetad,g2,’:m’)
legend(’No reaction on D, numeric sol’,’No reaction on D, analytic sol’,...
’Reaction on D analytic sol’,’Reaction on D numeric sol’)
xlabel(’\zeta’)
ylabel(’\Gamma’)
hold off

% Function containing the equations to be solved by the ODE solver


function d = equations(z,g)
kodab = 0.25;
l = 1;
th = sqrt(kodab*lˆ2);
dz = g(2);
ddz = thˆ2*g(1);
d = [dz;ddz];
23. PITOT TUBE 57

23. pitot tube


clear all
close all

%Initial data
g = 9.8065; % m/sˆ2
R = 8.31453; % J/(mol K)
D = 1.6; % pipe diamerter in m
Ptot = 1.01325e5; % Pa
Tg = 273.15 + 110; % K
Mgas = 28; % molecular weight g/mol
rholiq = 850; % kg/mˆ3
Cp = 1; % assume incompressible flow

%Velocity profiles North-South and West-East


hNS = [4.7 10.7 18.3 20.5 20.5 23.3 29.6 20.4 16.2 11.8]; % North-South
hEW = [2.1 8.6 15.4 16.2 21.3 21.3 20.5 16.8 13.3 2.2]; % East-West

%Now we calculate the velocity from the the measured heights. In order to
%do this, we first need to know the radial position of the measurement. We
%know there are five concentric rings, with the same area.
N = 5;
n = [1 2 3 4 5];
r = (D/2)*sqrt((2*n-1)/(2*N)); % position of the area center in each ring

%In order to plot the velocity profiles, we need an axis from wall to wall.
z = [fliplr(D/2-r) D/2+r];

%Next we need the preassure drop


delpNS = hNS*rholiq*g/1000;
delpEW = hEW*rholiq*g/1000;
rhogas = Ptot*Mgas/(R*Tg*1000);
vNS = Cp*sqrt(2*delpNS/rhogas);
vEW = Cp*sqrt(2*delpEW/rhogas);

%We add the boundary conditions


vNSw = [0 vNS 0];
vEWw = [0 vEW 0];
z = [0 z 1.6];
vmid = (vNSw+vEWw)./2; % Calculate the average velocity
z1 = [0:D/30:D]; % Adding a few extra points gives a smooth plot

%Do polynomial approximation


p2 = polyfit(z,vmid,2); % 2nd degree polynomial
p4 = polyfit(z,vmid,4); % 4th degree polynomial
sp = spline(z,vmid); % spline approximation
t2 = polyval(p2,z1);
t4 = polyval(p4,z1);
fsp = ppval(z1,sp);

plot(z,vmid,’*’,z1,t2)
title(’2nd degree polynomial’)
ylabel(’Average velocity, m/s’)
58 C. MATLAB CODE

xlabel(’Distance from left wall, m’)


axis([min(z),max(z),0,30])
legend(’Datapoints’,’Fitted profile’)
pause
plot(z,vmid,’*’,z1,t4)
title(’4th degree polynomial’)
ylabel(’Average velocity, m/s’)
xlabel(’Distance from left wall, m’)
axis([min(z),max(z),0,30])
legend(’Datapoints’,’Fitted profile’)
pause
plot(z,vmid,’*’,z1,fsp)
title(’Spline approximation’)
ylabel(’Average velocity, m/s’)
xlabel(’Distance from left wall, m’)
axis([min(z),max(z),0,30])
legend(’Datapoints’,’Fitted profile’)

%Compute the volumetric flow in mˆ3/h for the different cases.


Q_sp = num2str(round(quad(@pitot_integrand,0,D,[],[],sp)*3600));
Q_p2 = num2str(round(quad(@pitot_integrand,0,D,[],[],p2)*3600));
Q_p4 = num2str(round(quad(@pitot_integrand,0,D,[],[],p4)*3600));
disp([’Volumetric flow (cubic spline) : ’,Q_sp,’ mˆ3/h’])
disp([’Volumetric flow (2nd order polynomial): ’,Q_p2,’ mˆ3/h’])
disp([’Volumetric flow (4th order polynomial): ’,Q_p4,’ mˆ3/h’])

24. pitot integrand


function f = pitot_integrand(r,p)

%Function to calculate the integrand of the pitot-tube experiment.


%
% p = transferred polynomial coefficients for the velocity
% r = The position in the tube.
%
%The velocity is calculated from the polynomial coefficients. Since spline
%and polyfit uses different formats, we need to do a test and choose the
%appropriate function.

if isstruct(p) == 1
v = ppval(r,p);
else
v = polyval(p,r);
end
f = pi.*r.*v./2;

25. mingibb
%Equilibrium calculation n = minGibb(n0,t,p,m0,A) at a given temperature,
%pressure and total composition in ideal mixture phases.
%
%n0 = initial mole number vector [mol]
%t = temperature [K]
26. CSTR PROCESS CONTROL 59

%p = pressure [Pa]
%m0 = standard chemical potential (ideal gas at T)
%A = formula matrix (atoms x substances)
%n = final mole number vector [mol]

function[n] = minGibb(n0,t,p,m0,A)

%Parameters and physical quantities


r = 8.31453; % universal gas constant
p0 = 1e5; % standard state pressure
tol = 1e-6; % convergence tolerance
maxiter = 100; % maximum number of iterations
maxstep = 0.9; % maximum relative step length
epx = 1e-6; % arbitrarily small mole fraction
[nc,ns] = size(A); % number of atoms and substance

%Initialization
n = n0;
i = find(n==0);
n(i) = zeros(length(i),1) + sum(n)*epx;
e = ones(ns,1);

%Equilibrium calculation
for iter=1:maxiter
m = m0 + r*t*log(p/p0*n/sum(n));
D = diag(n)/(r*t);
lhs = [A*D*A’, A*n; (A*n)’, 0];
rhs = [A*D*m-A*(n-n0); n’*m];
x = inv(lhs)*rhs;
dn =-D*(m-A’*x(1:nc)) + n*x(nc+1);
step =-maxstep/min([-maxstep,min(dn./n)]);
n = n + step*dn;
if max(abs(dn./n))<tol; return; end
end

%Not converged
n = NaN*n;
return

26. CSTR process control


clear all
warning off

func = @cstr_time_derivatives; % make function handle

ca=2/3; T =400; x0=[ca T]; % equilibrium point: steady-state values


Q =5000; q =1; u0=[Q q]; % inputs
T1=350; caf=2; d0=[T1 caf]; % disturbances

t = [0 100];
[t0,y0] = ode15s(func,t,x0,[],u0,d0); % steady-state check

figure(1)
60 C. MATLAB CODE

subplot(2,1,1);
plot(t0,y0(:,1)), grid; title(’Steady-state behavior of the system’);
ylabel(’C_a [kmol/mˆ3]’);
subplot(2,1,2);
plot(t0,y0(:,2)), grid; xlabel(’t [s]’); ylabel(’T [K]’)

%Transient response to step changes


st = 2; % step order

u = u0; d=d0; d(1)=st*d(1); [t1,y1]=ode15s(func,t,x0,[],u,d); %T1


u = u0; d=d0; d(2)=st*d(2); [t2,y2]=ode15s(func,t,x0,[],u,d); %C_a final
u = u0; d=d0; u(1)=st*u(1); [t3,y3]=ode15s(func,t,x0,[],u,d); %Q
u = u0; d=d0; u(2)=st*u(2); [t4,y4]=ode15s(func,t,x0,[],u,d); %q

figure(2)
subplot(4,2,1); plot(t1,y1(:,1)), ylabel(’T1 [K]’), grid; title(’ca [kmol/mˆ3]’);
subplot(4,2,2); plot(t1,y1(:,2)), grid; title(’T [K]’);
subplot(4,2,3); plot(t2,y2(:,1)), ylabel(’caf [kmol/mˆ3]’), grid;
subplot(4,2,4); plot(t2,y2(:,2)), grid;
subplot(4,2,5); plot(t3,y3(:,1)), ylabel(’Q [kJ/min]’), grid;
subplot(4,2,6); plot(t3,y3(:,2)), grid;
subplot(4,2,7); plot(t4,y4(:,1)), ylabel(’q [mˆ3/min]’), grid; xlabel(’t [s]’)
subplot(4,2,8); plot(t4,y4(:,2)), grid; xlabel(’t [s]’)

%Linearization
[A,B,E] = ode_jacobian(func,[],x0,u0,d0);
C = eye(2);
D = zeros(2);
F = zeros(2);

%Stability, controllability, and observability


Co = ctrb(A,B);
Ob = obsv(A,B);

disp(’Eigenvalues of A’)
disp(eig(A))
disp(’Size Co, Rank Co’)
disp([size(Co,1), rank(Co)])
disp(’Size Ob, Rank Ob’)
disp([size(Ob,2), rank(Ob)])

Gss = ss(A,B,C,D);
Gdss = ss(A,E,C,D);
G = tf(Gss);
Gd = tf(Gdss);
[num,den] = tfdata(G);
[numd,dend] = tfdata(Gd);
sz = size(G);
i = 1:sz(1);
j = 1:sz(2);

%The data below are transferred to the Simulink file


[num11 ,den11 ] = tfdata(tf(num(1,1),den(1,1)),’v’); %g11
27. CSTR TIME DERIVATIVES 61

[num12 ,den12 ] = tfdata(tf(num(1,2),den(1,2)),’v’); %g12


[num21 ,den21 ] = tfdata(tf(num(2,1),den(2,1)),’v’); %g21
[num22 ,den22 ] = tfdata(tf(num(2,2),den(2,2)),’v’); %g22
[numd11,dend11] = tfdata(tf(numd(1,1),dend(1,1)),’v’); %gd11
[numd12,dend12] = tfdata(tf(numd(1,2),dend(1,2)),’v’); %gd12
[numd21,dend21] = tfdata(tf(numd(2,1),dend(2,1)),’v’); %gd21
[numd22,dend22] = tfdata(tf(numd(2,2),dend(2,2)),’v’); %gd22

%Poles and zeros


Poles_of_G = pole(Gss);
Zeros_of_G = zero(Gss);

w = logspace(-2,2);
figure(3)
sigma(G,w)
grid

%RGA
sz = size(G);
i = 1:sz(1);
j = 1:sz(2);
w1 = logspace(-3,1,200);
H = freqresp(G,w1);
for k=1:length(w1)
Hinv = inv(H(:,:,k));
RGA(i,j,k) = H(i,j,k).*Hinv’;
end
rga_diag = abs(RGA(1,1,:));
rga_offdiag = abs(RGA(1,2,:));

figure(4)
plot(w1,rga_diag(:),w1,rga_offdiag(:)); grid
xlabel(’Frequency [rad/s]’), ylabel(’Magnitude of the RGA Elements’)
legend(’\Lambda_{11} = \Lambda_{22}’,’\Lambda_{12} = \Lambda_{21}’)

27. CSTR time derivatives


function xdot = cstr_time_derivatives(t,x,u,d)

To = 400; % K
V = 4; % reactor volume [m3]
cp = 0.150; % heat capcity [kJ/kg*K]
E = 20000; % activation energy [kJ/kmol]
rho = 1000; % density [kg/m3]
ko = 0.5; % rate constant [minˆ-1]
R = 8.31453; % universal gas constant [kJ/K*kmol]
H = 1875; % reaction enthalpy [kJ/kmol]
ca = x(1); % concentration of A
T = x(2); % temperature
Q = u(1); % heat (input)
q = u(2); % volumetric flow (input)
T1 = d(1); % temperature in (disturbance)
caf = d(2); % concentration (disturbance)
k = ko*exp(-E/R*(1/T-1/To)); % Arrhenius rate
62 C. MATLAB CODE

dca_dt = (caf-ca)*q/V-k*ca; % concentration derivative


dT_dt = (T1-T)*q/V+H*k*ca/(rho*cp)+Q/(rho*cp*V); % temperature deriv
xdot = [dca_dt dT_dt]’;

28. ODE Jacobian


function [J_x,J_u,J_d] = ODE_Jacobian(fun,t,x,u,d)

% Evaluates the Jacobian of "fun" by the first order difference method.


%
% t = time
% x, u, d = input variables (arrays)
%
% The Jacobian is calculated by pertubing these variables, one at a time.

del = 1.0e-10;

%Calculation of matrix A (states x)


n_x = length(x);
J_x = [];
F = feval(fun,t,x,u,d);
for i=1:n_x
x_new = x;
pertub = x(i)*del + eps*100;
x_new(i) = x(i) + pertub;
F_new = feval(fun,t,x_new,u,d);
J_x = [J_x,((F_new-F)./pertub)];
end

% Calculation of matrix B (inputs u)


n_u = length(u);
J_u = [];
F = feval(fun,t,x,u,d);
for i=1:n_u
u_new = u;
pertub = u(i)*del + eps*100;
u_new(i) = u(i) + pertub;
F_new = feval(fun,t,x,u_new,d);
J_u = [J_u,((F_new-F)./pertub)];
end

% Calculation of matrix E (disturbances d)


n_d = length(d);
J_d = [];
F = feval(fun,t,x,u,d);
for i=1:n_d
d_new = d;
pertub = d(i)*del + eps*100;
d_new(i) = d(i) + pertub;
F_new = feval(fun,t,x,u,d_new);
J_d = [J_d,((F_new-F)./pertub)];
end
30. MW BINOP 63

29. mw from formula parser


%Chemical formula to molecular weight parser. Example on use:
%formula_to_mw_parser(’Ca(NO3)2(H2O)6’) returns the string
%’Ca+(N+O*3)*2+(H*2+O)*6’ which can be evaluated by Matlab if Ca, N, O and
%H are assigned Matlab variables. I.e. eval(’Ca+(N+O*3)*2+(H*2+O)*6’)
%should yield 272.1815.
%
%Author : Tore Haug-Warberg
%Version : April 30 2002 (THW)
%
%function [mwe] = mw_from_formula_parser(formula)
%
%formula = Chemical formula [string].
%mwe = Molecular weight expression [string].

function [mwe] = mw_from_formula_parser(formula)

%Parse the formula from right to left


mwe = formula(end);
right = mwe;
for left=formula(end-1:-1:1)
mwe = strcat(left,mw_binop(left,right),mwe);
right = left;
end

30. mw binop
%Binary operator (x o y) table for molecular
%weight parsing of chemical formulas.
%
%Author : Tore Haug-Warberg
%Version : April 30 2002 (THW)
%
%function [o] = mw_binop(x,y)
%
%x = Left operand [char].
%y = Right operand [char].
%o = Operator [char].

function [o] = mw_binop(x,y)

o = ’’;
if (isdigit(x))
if (islower(y)|isupper(y)|isleft(y))
o = ’+’;
end
elseif(islower(x))
if(isdigit(y))
o = ’*’;
elseif(islower(y))
o = ’<multiple_lower_case_letters>’;
elseif(isupper(y)|isleft(y))
o = ’+’;
64 C. MATLAB CODE

end
elseif(isupper(x))
if(isdigit(y))
o = ’*’;
elseif(isupper(y)|isleft(y))
o = ’+’;
end
elseif(isright(x))
if(isdigit(y))
o = ’*’;
elseif(islower(y))
o = ’<name_starts_with_lower_case>’;
elseif(isupper(y)|isleft(y))
o = ’+’;
end
elseif(isleft(x))
if(isdigit(y))
o = ’<name_starts_with_digit>’;
elseif(islower(y))
o = ’<name_starts_with_lower_case>’;
elseif(isright(y))
o = ’<empty_name>’;
end
end

%Verify that input string is a digit 0-9


function [i] = isdigit(s)
i = and(ge(abs(s),48),le(abs(s),57));

%Verify that input string is a left paranthesis (


function [i] = isleft(s)
i = eq(abs(s),40);

%Verify that input string is a right paranthesis )


function [i] = isright(s)
i = eq(abs(s),41);

%Verify that the input string is a lower case letter a-z


function [i] = islower(s)
i = and(ge(abs(s),97),le(abs(s),122));

%Verify that the input string is a lower case letter A-Z


function [i] = isupper(s)
i = and(ge(abs(s),65),le(abs(s),90));

31. make formula matrix


%Calculates the formula matrix for a specified list of chemical species.
%The complete list of 103 chemical elements is recognized by the parser.
%To add some flexibility a mixed list of strings and cell arrrays are
%allowed as input arguments:
%
%make_formula_matrix(’NaCl’,’KCl’,’MgCl2’,’CaCl2(H2O)6’);
%make_formula_matrix(’CH3(CH2)3OH’,{’H2’,’O2’,’H2O’},’CH3(CH2)COOH’);
31. MAKE FORMULA MATRIX 65

%make_formula_matrix({’CH3OH’,{’H2’,’O2’,’H2O’},’CO’,’CO2’});
%
%Note, however, that the output variables do not mimic the input cell
%structure, i.e. A will be a straightforward matrix and b will be a list.
%
%Author : Tore Haug-Warberg
%Version : April 30 2002 (THW)
%
%function [A,b] = make_formula_matrix(arg1,arg2,...,argN)
%
% A = Formula matrix [elements x species].
% b = Element name cell array [elements].
% arg1 = species formula (or cell array)
% arg2 = species formula (or cell array)
% ...
% argN = species formula (or cell array)

function [A,b] = make_formula_matrix(varargin);

persistent name;

if (isempty(name))
name = {’H’ ,’He’,’Li’,’Be’,’B’ ,’C’ ,’N’ ,’O’ ,’F’ ,’Ne’,’Na’,’Mg’,...
’Al’,’Si’,’P’ ,’S’ ,’Cl’,’Ar’,’K’ ,’Ca’,’Sc’,’Ti’,’V’ ,’Cr’,...
’Mn’,’Fe’,’Co’,’Ni’,’Cu’,’Zn’,’Ga’,’Ge’,’As’,’Se’,’Br’,’Kr’,...
’Rb’,’Sr’,’Y’ ,’Zr’,’Nb’,’Mo’,’Tc’,’Ru’,’Rh’,’Pd’,’Ag’,’Cd’,...
’In’,’Sn’,’Sb’,’Te’,’I’ ,’Xe’,’Cs’,’Ba’,’La’,’Ce’,’Pr’,’Nd’,...
’Pm’,’Sm’,’Eu’,’Gd’,’Tb’,’Dy’,’Ho’,’Er’,’Tm’,’Yb’,’Lu’,’Hf’,...
’Ta’,’W’ ,’Re’,’Os’,’Ir’,’Pt’,’Au’,’Hg’,’Tl’,’Pb’,’Bi’,’Po’,...
’At’,’Rn’,’Fr’,’Ra’,’Ac’,’Th’,’Pa’,’U’ ,’Np’,’Pu’,’Am’,’Cm’,...
’Bk’,’Cf’,’Es’,’Fm’,’Md’,’No’,’Lr’}’;
end

varargin = unpack(varargin); % make straight list


A = zeros(length(name),length(varargin)); % init formula matrix

for i=1:length(varargin)
[s,A(:,i)] = get_formula_vector(varargin{i},A(:,i),name,1.0);
end

i = find(sum(A,2)>0); % find non-zero rows in matrix A


A = A(i,:); % shrink matrix A to include non-zero rows only
b = {name{i}}’; % shrink the element list accordingly

%Recursive unpacking of input argument list


function [out] = unpack(in);
out = {}; % empty cell array
for i=1:length(in); % do for all members of the list
if (iscell(in{i})) % check if this is a new cell
tmp = unpack(in{i}); % recursive unpacking
out = {out{:},tmp{:}}; % augment output list
else %
out = {out{:},in{i}}; % augment output list
66 C. MATLAB CODE

end
end

32. get formula vector


%Adds stoichiometric coefficients for a specified chemical species using
%recursive string parsing.Eg [s,b]=get_formula_vector(’(CH3(CH2)2COOH)1.5’
%,[0 0 0],{’C’,’H’,’O’},1) returns s=’’ and b=[6 12 3]. The chemical ele-
%ments need not be specified in any particular order, but their order must
%coincide with the stoichiometric coefficients also specified in the input
%
%Author : Tore Haug-Warberg
%Version : March 10 2000 (THW)
%
%function [s,b] = get_formula_vector(s,b,name,factor)
%
% s = Chemical formula [string].
% b = Stoichiometric coefficients [vector].
% name = Recognized formula symbols [cell array].
% factor = External multiplier.
%

function [s,b] = get_formula_vector(s,b,name,factor)

coef = ’’; % initialize stoichiometric coefficient


sym = ’’; % initialize chemical symbol

while not(isempty(s)) % continue while string is non-empty


next = s(end); % pick next token from end of string
s = s(1:end-1); % decrement the formula string
if isletter(next) % token is a letter a-z or A-Z
sym = strcat(next,sym); % build a chemical symbol (He, Mg, etc.)
i = strmatch(sym,name,’exact’); % test against known symbols
if any(i) % SYM is a recognized symbol
b(i) = b(i) + factor*stoichiometry(coef); % increment stoich. coeff
coef = ’’; % reset the stoichiometric coefficient
sym = ’’; % reset the chemical symbol
end %
elseif isnumber(next) % token is a period or a number 0-9
coef = strcat(next,coef); % build a stoichiometric coefficient
sym = emptystring(sym); % test that SYM is empty
elseif isright(next) % token is a right paranthesis )
[s,b] = get_formula_vector(s,b,name, ... % call myself recursively
factor*stoichiometry(coef)); % increase premultiplic. factor
coef = ’’; % reset the stoichiometric coefficient
sym = emptystring(sym); % test that SYM is empty
elseif isleft(next) % token a left paranthesis (
sym = emptystring(sym); % test that SYM is empty
return; % return (from recursive call only)
end %
end %

sym = emptystring(sym); % test that SYM is empty


33. GREENHOUSE GASES FROM HYSYS 67

%Verify that input string is empty


function [s] = emptystring(s)
if (not(isempty(s)))
disp([’Unrecognized string: ’,s]);
end
sym = ’’;

%Verify that input string is a period or a number in the range 0-9


function [i] = isnumber(s)
i = or(and(ge(abs(s),48),le(abs(s),57)),eq(abs(s),46));

%Verify that input string is a left paranthesis (


function [i] = isleft(s)
i = eq(abs(s),40);

%Verify that input string is a right paranthesis )


function [i] = isright(s)
i = eq(abs(s),41);

%Convert input string to number (empty input string is treated as 1)


function [n] = stoichiometry(s)
if isempty(s)
n = 1;
else
n = str2num(s);
end

33. greenhouse gases from HYSYS


clear all % clear work space
warning(’off’) % avoid warning when the while loop terminates

component = {’Methane’,’Ethane’,’Propane’,’n-Butane’,’n-Pentane’}; % names


cnum = [1 2 3 4 5]; % Relative amount of carbon in each component

co2 = cell(4,2);
co2{1,1} = ’Stream’;
co2{1,2} = ’Co2 equivalent’;
fid = fopen(’..\data\HYSYS_report.txt’);
t = 1;
c = 1;
st = ’’;

% Read file into one long string.


while t>0;
t = fgets(fid);
st = strcat(st,t);
end
fclose(’all’); % close file
a = regexp(st,’(Material Stream:)’); % find start position of the streams
a(end+1) = length(st); % add end positions of the string to a vector

for i=1:length(a)-1
68 C. MATLAB CODE

stream = st(a(i):a(i+1)); % Look through the string one stream at a time


if ˜isempty(regexp(stream,’Material Stream: V’)) % Find wanted data
[tmp,tmp1] = regexp(stream,’(Overall Phase).*(Vapour Phase)’);
c = c + 1;
co2{c,2}(1) = 0; % initialize the container for CO2 equivalents
vap = stream(tmp:tmp1); % copy the interesting part
[tb,te] = regexp(vap,’Total ,\d*\.\d*’); % find the total stream
tmp2 = vap(tb:te);
[tb1,te1] = regexp(tmp2,’\d*\.\d*’); % pick out the numbers
total = str2num(tmp2(tb1:te1)); % convert from text to numbers
for j=1:length(component)
% find the position of each component, and take out the
% amount from the string. afterward the CO2 equivalent is
% calculated and added to the container.
[start,stop] = regexp(vap,strcat(component{j},’,\d*\.\d*’));
comp = vap(start:stop);
[start1,stop1] = regexp(comp,’\d+\.\d+’);
co2{c,2}(1) = co2{c,2}(1) + ...
str2num(comp(start1:stop1))*cnum(j)/total*100;
co2{c,1} = str2num(stream(19));
end
else
% do nothing, we are only seeking vapour data
end
end

disp(co2); %display the final result


APPENDIX D

Ruby code

1. greenhouse gases from HYSYS


#read output file and remove end-of-line character
f = File.open(’..\data\HYSYS_report.txt’).read.gsub!(/\n/,’’)

#Split file into sections of stream data. Remove non-vapour streams


arr = f.split(/(?=Material Stream: V)/).each{|i|
i.gsub!(/Material Stream: [ˆV].*/,’’)
}

#Create hash with key="component name" and value="relative amount of C"


co2 = {"Methane",1.0,"Ethane",2.0,"Propane",3.0,
"n-Butane",4.0,"n-Pentane",5.0}

#Create empty Hash to store the final result. Default flow is zero.
hsh = Hash.new(0.0)

#Define some practical regular expressions


streams = Regexp.new(’Material Stream: V(\d)’)
totflow = Regexp.new(’COMPONENTS,MOLAR.*Total ,(\d*\.\d*).*Vapour Phase’)
vapflow = Regexp.new(’COMPONENTS,MOLAR.*Vapour Phase’)
cmpflow = Regexp.new(’([a-z]\-[A-Z][a-z]*|[A-Z][a-z]*),(\d*\.\d*)’)

#Scan the vapor stream sections of the output file


arr.each{|i|
n = i.scan(streams).to_s # vapor stream number
t = i.scan(totflow).to_s.to_f # total stream flow
i.scan(vapflow).to_s.scan(cmpflow).each{|j| # each component flow
hsh[n] += co2[j.first]*j.last.to_f/t*100 # % CO2 equivalent
}
}

#Make a report
hsh.each{|n,p|puts "Stream V#{n}: #{p.to_i}% CO2 of total molar flow"}

69
APPENDIX E

Data files

1. pages from water vapor pressure data


%PDOUS71
%Douslin, D.R.
%J. Chem. Thermodynamics, 3, 187 (1971).
% T90(K) P(MPa)
270.651 .0005088
273.150 .0006114
273.160 .0006121
274.150 .0006573
275.150 .0007061
276.149 .0007587
277.149 .0008137
278.149 .0008730
280.649 .0010370
283.148 .0012291
288.147 .0017066
285.647 .0014485
290.646 .0020007
293.145 .0023395
%
%PHANA84
%Hanafusa,H.,Tsuchida,T.,Kawai.,Sato,H.,Uematsu,M.,and Watanabe, K.
%Proc. 10th ICPS, Moscow 1984, 180;High Temp.-High Pres., 15, 311(1983).
% T90(K) P(MPa)
643.174 21.0502000
645.607 21.6715000
645.607 21.6705000
646.106 21.7997000
646.356 21.8645000
646.607 21.9309000
646.607 21.9303000
646.857 21.9974000
%
%PKELL85
%Kell, G.S., McLaurin, G.E., and Whalley, E.
%Phil. Trans. R. Soc. London, 315A, 235 (1985).
% T90(K) P(MPa)
423.133 .4759000
423.134 .4759000
423.133 .4758000
423.108 .4752000
423.112 .4757000
448.114 .8918000
448.114 .8918000

71
72 E. DATA FILES

473.109 1.5536000
473.109 1.5535000
498.107 2.5474000
498.118 2.5479000
523.168 3.9780000
523.168 3.9772000
548.108 5.9416000
548.108 5.9416000
573.111 8.5821000
573.110 8.5822000
598.110 12.0446000
598.111 12.0443000
623.183 16.5370000
623.183 16.5370000
623.109 16.5196000

2. pages from water density 1bar data


%Kell, G.S.
%J. Chem. Eng. Data, 20(1) 97 (1975).
% T90(K) P(MPa) d(kg/m3)
273.150 .101325 999.84260
278.147 .101325 999.96690
283.144 .101325 999.70311
288.141 .101325 999.10362
293.138 .101325 998.20874
298.136 .101325 997.05027
303.134 .101325 995.65331
308.132 .101325 994.03845
313.130 .101325 992.22289
318.128 .101325 990.22074
323.137 .101325 988.03930
328.125 .101325 985.70316
333.134 .101325 983.20192
338.124 .101325 980.56279
343.132 .101325 977.77266
348.124 .101325 974.85613
353.123 .101325 971.80450
358.123 .101325 968.62628
363.123 .101325 965.32527
373.124 .101325 958.36664
383.126 .101325 950.94723
393.127 .101325 943.07942
403.130 .101325 934.76863
413.132 .101325 926.01485
423.134 .101325 916.81308
%
%Owen, B.B., White, J.R., and Smith, J.S.
%J. Am. Chem. Soc., 78, 3561 (1956).
% T90(K) P(MPa) d(kg/m3)
313.130 .101325 992.22250
318.128 .101325 990.21900
323.127 .101325 988.04030
328.125 .101325 985.69720
4. PAGES FROM HYSYS REPORT 73

333.124 .101325 983.19870


338.124 .101325 980.55310
343.124 .101325 977.76690
348.123 .101325 974.84530
353.123 .101325 971.79200
358.123 .101325 968.61060

3. water viscosity 1bar data


%Barrow, G. M., Physical Chemistry, 3rd ed.,
%McGraw-Hill, 535 (1973).
% T(C) P(MPa) visc(kg/m*s)
0 .101325 0.001792
20 .101325 0.001005
40 .101325 0.000656
60 .101325 0.000469
80 .101325 0.000356
100 .101325 0.000284

4. pages from HYSYS report


Material Stream: V3,Fluid Package: Basis-1
,
,Property Package: Peng Robinson CONDITIONS
,Overall,Vapour Phase,Liquid Phase,,
Vapour / Phase Fraction ,1.0000,1.0000,0.0000,,
Temperature: (C),45.00,45.00,45.00,,
Pressure: (kPa),3924,3924,3924,,
Molar Flow (kgmole/h),42.19,42.19,0.0000,,
Mass Flow (kg/h),1223,1223,0.0000,,
Std Ideal Liq Vol Flow (m3/h),3.090,3.090,0.0000,,
Molar Enthalpy (kJ/kgmole),-8.852e+004,-8.852e+004,-1.179e+005,,
Molar Entropy (kJ/kgmole-C),158.3,158.3,114.1,,
Heat Flow (kJ/h),-3.735e+006,-3.735e+006,0.0000,,
Liq Vol Flow @Std Cond (m3/h),,,0.0000,,
COMPOSITION
Overall Phase ,Vapour Fraction 1.0000
,
COMPONENTS,MOLAR FLOW,MOLE FRACTION,MASS FLOW,MASS FRACTION,
LIQUID VOLUME,LIQUID VOLUME
, (kgmole/h), , (kg/h), ,FLOW (m3/h),FRACTION
Methane,17.7435,0.4206,284.6569,0.2328,0.9508,0.3077
Ethane,13.4946,0.3199,405.7803,0.3319,1.1408,0.3692
Propane,7.8865,0.1869,347.7726,0.2845,0.6864,0.2221
n-Butane,2.6142,0.0620,151.9480,0.1243,0.2605,0.0843
n-Pentane,0.4487,0.0106,32.3749,0.0265,0.0514,0.0166
Total ,42.1875,1.0000 ,1222.5327,1.0000 ,3.0899,1.0000
Vapour Phase,Phase Fraction 1.000
,
COMPONENTS,MOLAR FLOW,MOLE FRACTION,MASS FLOW,MASS FRACTION,
LIQUID VOLUME,LIQUID VOLUME
, (kgmole/h), , (kg/h), ,FLOW (m3/h),FRACTION
Methane,17.7435,0.4206,284.6569,0.2328,0.9508,0.3077
Ethane,13.4946,0.3199,405.7803,0.3319,1.1408,0.3692
74 E. DATA FILES

Propane,7.8865,0.1869,347.7726,0.2845,0.6864,0.2221
n-Butane,2.6142,0.0620,151.9480,0.1243,0.2605,0.0843
n-Pentane,0.4487,0.0106,32.3749,0.0265,0.0514,0.0166
Total ,42.1875,1.0000 ,1222.5327,1.0000 ,3.0899,1.0000
Liquid Phase,Phase Fraction 0.0000
,
COMPONENTS,MOLAR FLOW,MOLE FRACTION,MASS FLOW,MASS FRACTION,
LIQUID VOLUME,LIQUID VOLUME
, (kgmole/h), , (kg/h), ,FLOW (m3/h),FRACTION
Methane,0.0000,0.1091,0.0000,0.0404,0.0000,0.0664
Ethane,0.0000,0.2463,0.0000,0.1710,0.0000,0.2363
Propane,0.0000,0.3223,0.0000,0.3282,0.0000,0.3184
n-Butane,0.0000,0.2364,0.0000,0.3172,0.0000,0.2673
n-Pentane,0.0000,0.0859,0.0000,0.1431,0.0000,0.1117
Total ,0.0000,1.0000 ,0.0000,1.0000 ,0.0000,1.0000

You might also like