Nothing Special   »   [go: up one dir, main page]

Appendix A: Linking The Bzzmath Library To Matlab

Download as pdf or txt
Download as pdf or txt
You are on page 1of 9

269

Appendix A: Linking the BzzMath Library to Matlab

A.1
Introduction

The purpose of this appendix is to provide a viable code to integrate the


BzzMath library into Matlab. The guidelines for implementing a MEX function
are available to allow user-created functions and libraries written in C++ (or
Fortran) to be used into Matlab as built-in functions.
The appendix describes this mixed-language in the same manner that we
adopted for C++-Fortan mixed language in the appendices of Vol. 2, Buzzi-
Ferraris and Manenti 2010b, that is, through the use of very simple examples to
highlight the main programming difculties:

 The rst example is a sum of two numbers


 The second one is a ash drum separator

A.2
BzzSum Function

The goal is to create a function (BzzSum) written in C++ language that exploits
the BzzMath libraries in the Matlab environment. The function requires the
following information as input:

 A numerical vector (the values for which we are searching for the sum)
 The vector size

Thus, those inputs are 1 double and 1 int. The function has a double as
output: the sum.
A typical function consists of three parts: header, functions, and MEX
function.

Differential and Differential-Algebraic Systems for the Chemical Engineer: Solving Numerical Problems,
First Edition. Guido Buzzi-Ferraris and Flavio Manenti.
2014 Wiley-VCH Verlag GmbH & Co. KGaA. Published 2014 by Wiley-VCH Verlag GmbH & Co. KGaA.
270 Appendix A: Linking the BzzMath Library to Matlab

A.2.1
Header File

The header le consists of all the #include and #dene statements:


#dene BZZ_COMPILER 1
#include <math.h>
#include mex.h
#include BzzMath.hpp
//With complete path according to the compiler
#dene numeri_in prhs[0]
#dene n_in prhs[1]
#dene somma_out plhs[0]
Be careful to declare the right path for the .hpp le.

A.2.2
MEX Function

It consists of the nal part of the program:


void mexFunction(int nlhs,mxArray *plhs[],
int nrhs,const mxArray *prhs[])
{
double *somma;
double *numeri;
int n;
if (nrhs != 2)
mexErrMsgTxt(Two input arguments required);
else if (nlhs > 1)
mexErrMsgTxt(Too many output arguments);
somma_out = mxCreateDoubleMatrix (1,1,mxREAL);
somma = mxGetPr(somma_out);
numeri = mxGetPr(numeri_in);
n = mxGetScalar(n_in);
sommatoria(numeri, somma, n);
return;
}

The structure of the function is of standard form. It has a prototype


void mexFunction(int nlhs,mxArray *plhs[],int nrhs,
const mxArray *prhs[])
that contains the following terms:
 nlhs: number left-hand side (number of outputs)
 *plhs[]: array of left-hand side
A.2 BzzSum Function 271

 nrhs: number right-hand side (number of inputs)


 *prhs[]: array of left-hand side
 mxArray: it is a particular kind of variable used in the MEX functions; it
contains double elements
There is the need to declare pointers and variables used by the C++ function
that we wish to recall into Matlab:
double *somma;
double *numeri;
int n;

Note that while the double variables need to be used as pointers, the int
variables can be used as is. It will be claried later in the appendix.
It is also suitable to immediately check the consistency of user input/output
information:
if (nrhs != 2)
mexErrMsgTxt(Two input arguments required);
else if (nlhs > 1)
mexErrMsgTxt(Too many output arguments);
It is necessary to create an array for the output and assign the input array to
the function pointer:
somma_out = mxCreateDoubleMatrix (1,1,mxREAL);
somma = mxGetPr(somma_out);
numeri = mxGetPr(numeri_in);
n = mxGetScalar(n_in);

The output of the matrix must be created with a specic statement. The com-
mands to assign the pointer to different variables are as follows:

 mxGetPr in case of double


 mxGetScalar in case of int
Mind that the int are not used as pointers, but as variables. Thus, the call to
the C++ function is
sommatoria(numeri, somma, n);
A.2.3
C++ Part

Also the portion in C++ have to be predisposed. The code is


void sommatoria (double numeri[],double *Somma,int n)
{
BzzVector A(n);
for (int i=1;I<=n;i++)
{
A[i] = numeri[i-1];
272 Appendix A: Linking the BzzMath Library to Matlab

}
*Somma = A.GetSumElements();
return;
}

The program is intentionally trivial to allow the focus on the structure of the
function. A BzzVector is adopted in this case and a for loop is implemented
to assign the elements of the mxArray to the BzzVector.
The function GetSumElements of BzzMath library is used and passed to
the output pointer.

A.2.4
Compiling

First, take care that the appropriate version of BzzMath is present into the work
folder (see the ReadMe le). Next, the following steps have to be accomplished:

 Type mexsetup
 Choose the Visual Studio Compiler
 Type mex BzzSum.cpp BzzMath.lib to compile
 the le BzzSum.mexw32 is created
 Call the function as a common Matlab function:

numeri = [1:4];
n=length(numeri);
BzzSum(numeri,n)

It results in 10.

A.3
Chemical Engineering Example

The case of ash drum separator is considered (Figure A.1); it is a nonlinear


algebraic system and the class BzzNonLinearSystem is required to solve it
(Buzzi-Ferraris and Manenti, 2014).
The concept is how to solve a ash drum separator problem using the infor-
mation provided with Matlab and an algorithm of the BzzMath library. The
ash feedstock is toluene and 1-butanol; there are six unknowns: molar fraction
of toluene in the liquid, molar fraction of 1-butanol in the liquid, molar fraction
of toluene in the vapor, molar fraction of 1-butanol in the vapor, liquid molar
ow rate, and temperature.
Five data must be passed to the algorithm: vapor molar ow rate, pressure,
feed molar ow rate, and feed composition.
All the other parameters are given and included in the model.
A.3 Chemical Engineering Example 273

V, yt , yb

F, zt , zb P T

L, xt , xb

Figure A.1 Qualitative representation of ash molar fraction; T = temperature; P = pressure;


drum separator. F = feed ow rate; L = liquid t = toluene; and b = 1-butanol. Unknowns are
ow rate; V = vapor ow rate; z = feed molar in italics, whereas the rest are assigned data.
fraction; x = liquid molar fraction; y = vapor

The resulting model for the system is


Fzt V yt Lxt
Fzb V yb Lxb
y t k 1 xt
y b k 2 xb
yt y b x t x b
F V L
1345:087
6:95508
10 219:516 T
k1
P
1781:719
8:19659
10 217:675 T
k2
P
The model is implemented in C++ (le BzzFlash.cpp).
The header le is as follows:
#dene BZZ_COMPILER 1
#include <math.h>
#include mex.h
#include YourPath\BzzMath.hpp
#dene dati_in prhs[0] //Vector of values
#dene n_dati_in prhs[1] //Number of elements
#dene incognite_in prhs[2] //Guesses of unknowns
#dene n_incognite_in prhs[3] //Number of unknowns
FILE *res; //To print in C++
FILE *chk;
In such a le it is necessary to dene the appropriate compiler (see the ReadMe
le of the BzzMath library), the libraries needed (mex.h and BzzMath.hpp are
mandatory), the input data of the problem (in this case, dati_in, n_dati_in,
incognite_in, n_incognite_in), and the pointers to the les that will be
opened.
274 Appendix A: Linking the BzzMath Library to Matlab

A.3.1
Denition of a New Class

A new class has to be dened:


class NLSO : public BzzMyNonLinearSystemObject
{
private:
BzzVector data;
public:
NLSO(BzzVector &dat)
{data = dat;};
virtual void GetResiduals(BzzVector &Inc,
BzzVector &eq);
virtual void ObjectBzzPrint(void);
};
void NLSO::ObjectBzzPrint(void)
{
::BzzPrint(Object Print for MyObject);
data.BzzPrint(Data);
}
Since data are passed by the Matlab interface and not inserted in the algo-
rithm, a new class derived from BzzNonLinearSystemObject must be cre-
ated (see BzzNonLynearSystemObject tutorial or the Vol. 3, Buzzi-Ferraris
and Manenti, 2014).
Calling the function:
NLSO <object;>(<vector of data>)
the data will be inserted in the model and saved in an object:
void NLSO::GetResiduals(BzzVector &Inc, BzzVector &eq)
{
double x1 = Inc[1];
double x2 = Inc[2];
double y1 = Inc[3];
double y2 = Inc[4];
double L = Inc[5];
double T = Inc[6];
double V = data[1];
double P = data[2];
double F = data[3];
double z1 = data[4];
double z2 = data[5];
double k1 = pow(10.,6.95508 - 1345.087 /
(219.516 + T)) / P;
double k2 = pow(10.,8.19659 - 1781.719 /
(217.675 + T)) / P;
A.3 Chemical Engineering Example 275

eq[1] = F * z1 - V * y1 - L * x1;
eq[2] = F * z2 - V * y2 - L * x2;
eq[3] = y1 - k1 * x1;
eq[4] = y2 - k2 * x2;
eq[5] = y1 + y2 - x1 - x2;
eq[6] = F - V - L;
}
The virtual function GetResiduals will contain the model of the ash. Note
that in the model appears the vector data used in the denition of the new class
NLSO.

A.3.2
Main Program in C++

The main program is


void main(double dati[], int n_dati,
double incognite[], int n_incognite)
{
res = fopen(Risultati.ris,w);
chk = fopen(Check.txt, w);
BzzVector Dati(n_dati);
BzzVector Inc(n_incognite);
for (int i=1;I<=n_dati;i++)
{
Dati[i] = dati[i-1]; //Gap C++ array & BzzVector
}
for (int i=1;I<=n_incognite;i++)
{
Inc[i] = incognite[i-1];
}
...
The les needed are opened or created. The data coming from Matlab are
stored into BzzVector variables so that they can be used with the BzzNonLi-
nearSystem class:
NLSO obj(Dati);
BzzNonLinearSystemObject nls(Inc, &obj);
double tA = 1.e-15;
double tR = 1.e-10;
nls.SetTolerance(tA,tR);
nls();
BzzVector Soluzione;
BzzVector Valori;
nls.GetSolution(&Soluzione, &Valori); //Unknowns
276 Appendix A: Linking the BzzMath Library to Matlab

fprintf(res,\n t frac. in L: %g \n,Soluzione[1]);


fprintf(res,\n b frac. in L: %g \n,Soluzione[2]);
fprintf(res,\n t frac. in V: %g \n,Soluzione[3]);
fprintf(res,\n b frac. in V: %g \n,Soluzione[4]);
fprintf(res,\n T: %g \n,Soluzione[6]);
fprintf(res,\n L: %g \n,Soluzione[5]);
fclose(res);
for (int i = 1;I<=n_incognite;i++)
{fprintf(chk,\n Eq. %d: %g \n,i,Valori[i]);}
fclose(chk);
}

The vector Dati is passed to the object obj. The solution of the system is
evaluated and stored in the Soluzione vector and the residuals of equations
are stored in the Valori vector. The outputs are printed in appropriate les.
//C++ part MEX function
void mexFunction(
int nlhs,
mxArray *plhs[],
int nrhs,
const mxArray *prhs[]
)
{
double *incognite;
int n_incognite;
double *Soluzione;
double *dati;
int n_dati;
if (nrhs != 4)
mexErrMsgTxt(4 input arguments required);
else if (nlhs > 0)
mexErrMsgTxt(Too many output arguments);
dati = mxGetPr(dati_in); //for pointers
n_dati = mxGetScalar(n_dati_in); //for scalars
n_incognite = mxGetScalar(n_incognite_in);
incognite = mxGetPr(incognite_in);
main(dati,n_dati,incognite,n_incognite);
return;
}

Pointers to the data coming from Matlab are created. A check for the number
of inputs and outputs is performed. The pointers are associated with the data
variables and the main function is called.
A.3 Chemical Engineering Example 277

A.3.3
Main Program in Matlab

The Matlab code is


mex BzzFlash.cpp BzzMath.lib;
dati = [25. 760. 100. .3 .7];
n_dati = length(dati);
inc = [.3 .7 .3 .7 50. 100.]; %Guesses
n_inc = length(inc);
BzzFlash(dati,n_dati,inc,n_inc);

The le is compiled and a le BzzFlash.mexw32 is created. The function


BzzFlash is recognized by Matlab. Vectors of data and rst guess are created.
The BzzFlash function is called and the problem is solved. The les Risul-
tati.ris and Check.txt are created.

You might also like