CHAPTER 13: Structures, Cells and Other Arays

Data used in the Chemical Engineering modules has been stored in matrices. Since matrices must be rectangular and can hold either numeric or character data, this placed limits on the way the data was stored during use in the programs. It also made it rather difficult to extract data from the property data files and put the data in the arrays where they would be used. In Matlab versions through 4.2 this was the only choice for storage of data. Now Matlab 5.1 offers several choices that have definite advantages since they can store mixed (both numeric and character) data, can store data in higher dimensional arrays than matrices and can be used to avoid having to spend as much effort in storing and extracting the data from files. This chapter will show the basic ideas that were used in utilizing structures in the start301 program developed by Mike Cohen during the Summer of 1998.

First let's a brief review of the way chemical property data is stored in a chemical engineering session. The main types of arrays are:

Table 13.1 Types of Arrays Used in ceng301 Modular Simulation

Type of Array

Example

Stores

Might hold

numeric scalar

nc

Number of Compounds
4

string matrix

cnms

Compound Names
 ammonia 
 nitrogen
 hydrogen
 argon 

numeric vector

mw

molecular weights
   17.0300
   28.0130
    2.0160
   39.9480

numeric matrix

Aabc

Antoine Constants
  15.494    13.45    12.78
  13.915  2363.20   658.22
 232.320   832.78   -22.62
  -2.854     8.08     2.36
For a complete list of compound properties stored by use of the start program see the section on this program in the Ceng 301 Notes.

Cells could be used to store all four types of data in the same array. We will give an example where data for the same four compounds in Table 13.1 were put in a file with start301a and loaded with start301b (these are the programs that start301 replaced. We see the familiar listing of compounds and reactions at the end of this process:

Here are your compounds' formulae and names:
No. Formula Name
  1  NH3   ammonia 
  2  N2    nitrogen
  3  H2    hydrogen
  4  Ar    argon   
Here are your reactions:
  1  N2  + 3 H2   --> 2 NH3 
 


We can consturct an empty cell array as indicated in the help notes about the command by that name:

»help cell
 
 CELL  Create cell array.
    CELL(N) is an N-by-N cell arrray of empty matrices.
 
    CELL(M,N) or CELL([M,N]) is an M-by-N cell array of empty
    matrices.
 
    CELL(M,N,P,...) or CELL([M N P ...]) is an M-by-N-by-P-by-...
    cell array of empty matrices.
 
    CELL(SIZE(A)) is a cell array the same size as A containing
    all empty matrices.
 

Thus we can create a cell to hold the data shown in Table 13.1 by:

»celldat=cell(4,1)  <-- Making a empty, cell, column vector with place
celldat =               for four "things".
     []
     []
     []
     []
»celldat{1,1}=nc   <-- Putting nc in the first place. 
                  Note use of "{" and "}"
celldat = 
    [4]
     []
     []
     []
»celldat{2,1}=cnms; <-- Adding cnms in the second place.
»celldat{3,1}=mw;   <-- mw is put in the third place
»celldat{4,1}=Aabc; <-- The matrix Aabc is put in the fourth place.
»celldat            <-- When we list the cell, we see the data we placed
celldat =               only in the scalar: nc
    [         4]    <-- nc is 4
    [4x9 char  ]    <-- cnms is a 4 by 9 character matrix.
    [4x1 double]    <-- mw is a numeric column vector with 4 elements
    [4x3 double]    <-- Aabc is a 4 by 3 numeric matrix

The use of braces ( "{" and "}") to access the contents of a cell must be remembered. If you use parentheses instead you will find that it can lead to confusion:

»celldat(1,1)  <-- This produces a cell with the number 4 in it
ans = 
    [4]
»celldat{1,1}  <-- This gives us the number 4
ans =
     4
»celldat(4,1)  <-- A cell having Aabc in it
ans = 
    [4x3 double]
»celldat{4,1}  <-- The numeric values of the coefficients
ans =
   1.0e+03 *
    0.0155    2.3632   -0.0226
    0.0134    0.6582   -0.0029
    0.0128    0.2323    0.0081
    0.0139    0.8328    0.0024
 

The same data may also be placed in a structure. Here is information to get started:

»help struct 

STRUCT Create or convert to structure array.

S = STRUCT('field1',VALUES1,'field2',VALUES2,...) 

creates a structure array with the specified fields and values. The value arrays VALUES1, VALUES2, etc. must be cell arrays of the same size, scalar cells or single values. Corresponding elements of the value arrays are placed into corresponding structure array elements.

The size of the resulting structure is the same size as the value cell arrays or 1-by-1 if none of the values is a cell.

STRUCT(OBJ) 

converts the object OBJ into its equivalent structure. The class information is lost.

Example:

s = struct('type',{'big','little'},'color','red','x',{3 4}) 
 
See also CLASS, CELL, GETFIELD, SETFIELD, RMFIELD, FIELDNAMES.

From this help, we can make a structure with the same data we put in celldat:

»strucdat=struct('nc',nc,'cnms',cnms,'mw',mw,'Aabc',Aabc)
strucdat = 
      nc: 4
    cnms: [4x9 char  ]
      mw: [4x1 double]
    Aabc: [4x3 double]

Now if we want to access this data that we stored, we can use:

»strucdat.nc
ans =
     4
»strucdat.mw
ans =
   17.0300
   28.0130
    2.0160
   39.9480

Matlab structures seem to offer the most efficient way to store and then retreive data. The main advantages of structures over cells are:

Two functions and a starting data base with part of the data in our data files were developed to explore the possibility of replacing our starting programs start301a and start301b with a single Matlab program. Help applied to the commands: fieldnames, getfield and setfield was used to understand ways that this might be done. The example programs: mkstruct and mkvars illustrate some of the advantages of using structures.

»help fieldnames

FIELDNAMES Get structure field names.

    NAMES = FIELDNAMES(S) 

returns the structure field names associated with the structure S as a cell array of strings.

See also GETFIELD, SETFIELD.

 

You must be careful in using fieldnames since it returns a cell array.

>> fnames=fieldnames(strucdat) 
fnames = 
    'nc'
    'cnms'
    'mw'
    'Aabc'


The class command tells us that:

 
>> class(fnames)
ans =
cell


One element of fnames may look like a string, but it is not.

 
>> class(fnames)
ans =
cell
>> fn1=fnames(1)
fn1 = 
    'nc'
>> 'nc'==fn1
??? Function '==' not defined for variables of class 'cell'.
>> class(fn1)
ans =
cell


If we want the contents of a cell, we need to use braces:

>> fn1=fnames{1}
fn1 =
nc
>> 'nc'==fn1
ans =
     1     1
>> class(fn1)
ans =
char
 

»help getfield

GETFIELD Get structure field contents.

    F = GETFIELD(S,'field') 

returns the contents of the specified field. This is equivalent to the syntax F = S.field.

S must be a 1-by-1 structure.

    F = GETFIELD(S,{i,j},'field',{k})

is equivalent to the syntax

    F = S(i,j).field(k).  

In other words,

    F = GETFIELD(S,sub1,sub2,...) 

returns the contents of the structure S using the subscripts or field references specified in sub1,sub2,etc. Each set of subscripts in parentheses must be enclosed in a cell array and passed to GETFIELD as a separate input. Field references are passed as strings.

See also SETFIELD, FIELDNAMES.

»help setfield

SETFIELD Set structure field contents.

    S = SETFIELD(S,'field',V) 

sets the contents of the specified field to the value V. This is equivalent to the syntax S.field = V. S must be a 1-by-1 structure. The changed structure is returned.

    S = SETFIELD(S,{i,j},'field',{k},V) 

is equivalent to the syntax

    S(i,j).field(k) = V;

In other words,

    S = SETFIELD(S,sub1,sub2,...,V) 

sets the contents of the structure S to V using the subscripts or field references specified in sub1,sub2,etc. Each set of subscripts in parentheses must be enclosed in a cell array and passed to SETFIELD as a separate input. Field references are passed as strings.

See also GETFIELD, FIELDNAMES.

The function mkstruct allows us to add data for one compound to an existing structure. The fields in the existing structure are identical to the names of data variables set by start301a and start301b. Here is a listing of the program.

The function mkvars extracts all the data in a structure like the one created with mkstruct and puts the data in variables of the same names as the fields in the structure. All the compounds are added to these variables. Here is a listing of mkvars.

Note that the mkvars function returns a string with the command that makes all the variables global. Thus if this returned string is evaled, we will have a session ready to be used in the 301 modules.

The function mkstruct was used to produce a structure holding twelve types of data for twenty compounds. This procedure produced a structure called stdat. It was saved as the file: /home/ceng301/datbas/struct1.mat. Here is an example of using the mkstruct function to add the compound ethanol to the structure. First we use start301a and start301b:

»start301b
Copyright 1996 Rice University
All rights reserved
 
If you have not run the FORTRAN program start301a to
produce a data file, do so now or you can just set
the names without any data.  A blank reply for
the file name will let you just set the names.
Give the name of your data file:waterethanol
How many streams will there be?1
Here are your compounds' formulae and names:
No. Formula Name
  1  H2O      water  
  2  C2H5OH   ethanol

Next we load the file that had data for our twenty compounds:

»load struct1
»who
 
Your variables are:
 
Aabc      StStdh    cpl       form      icpv      stdat     
AcF       StdhkJ    cps       hcpl      mw        
Gibb      TbpK      cpv       hcps      nc        
LJones    Tdeg      critP     hcpv      ne        
LhlvkJ    TmpK      critT     icpl      ns        
LhslkJ    cnms      critZ     icps      nst
 

The structure stdat has the form shown by:

»stdat
 
stdat = 
 
20x1 struct array with fields:
    cnms
    form
    mw
    Aabc
    LhlvkJ
    StStdh
    StdhkJ
    TbpK
    cpl
    cpv
    hcpl
    hcpv
 

Here is the data for the first compound in the structure:

»stdat(1)
 
ans = 
 
    cnms: ' benzene         '
    form: ' C6H6        '
      mw: 78.1130
    Aabc: [14.1600 2.9488e+03 -44.5630]
  LhlvkJ: 30.7600
  StStdh: 2
  StdhkJ: 82.9300
    TbpK: 353.2600
     cpl: [-7.2732 0.7705 -0.0016 1.8979e-06]
     cpv: [18.5800 -0.0117 0.0013 -2.0790e-06 1.0500e-09]
    hcpl: [4.7448e-10 -5.4937e-07 3.8527e-04 -0.0073 28.4482]
    hcpv: [2.1000e-13 -5.1975e-10 4.2500e-07 -5.8700e-06 0.0186 70.2605]
 

Let's add the ethanol data to this data structure:

»stdat2=mkstruct(stdat',2) <-- Note transpose of stdat
 
stdat2 = 
 
1x21 struct array with fields:
    cnms
    form
    mw
    Aabc
    LhlvkJ
    StStdh
    StdhkJ
    TbpK
    cpl
    cpv
    hcpl
    hcpv
 
»stdat2(21)<-- Seeing what was added for ethanol
 
ans = 
 
   cnms: ' ethanol'
   form: ' C2H5OH'
     mw: 46.0690
   Aabc: [16.1950 3.4235e+03 -55.7150]
 LhlvkJ: 38.5800
 StStdh: 2
 StdhkJ: -234.8000
   TbpK: 351.4800
    cpl: [-325.1300 4.1379 -0.0140 1.7035e-05]
    cpv: [17.6900 0.1495 8.9480e-05 -1.9730e-07 8.3170e-11]
   hcpl: [4.2588e-09 -4.6767e-06 0.0021 -0.3251 -272.9021]
   hcpv: [1.6634e-14 -4.9325e-11 2.9827e-08 7.4750e-05 0.0177 -247.1590]

Let's save this new structure and reload it into a clear workspace, then use mkvars create a new set of variables for use in the 301 modules.

»save structnew stdat2
»clear
»load structnew
»who
 
Your variables are:
 
stdat2

Now use mkvars:

»mkvars(stdat2)
 
ans =
 
global cnms form mw Aabc LhlvkJ StStdh StdhkJ TbpK cpl cpv hcpl hcpv 
 
»eval(ans) <-- This makes the variables global (you could also do
»who           do it by: eval(mkvars(stdat2)).
 
Your variables are:
 
Aabc      StdhkJ    cnms      form      mw        
LhlvkJ    TbpK      cpl       hcpl      stdat2    
StStdh    ans       cpv       hcpv      
 
»cnms  <-- We can now look at all the compounds in struct1 plus
           ethanol that we added in the session.
cnms =
 
 benzene         
 n-butane        
 n-butanol       
 n-butyric acid  
 n-heptane       
 n-hexadecane    
 n-hexane        
 n-octane        
 n-pentane       
 n-propanol      
 neon            
 nicotinic acid  
 nitric acid     
 nitric oxide    
 nitrogen        
 nitrogen dioxide
 nitromethane    
 nitrous oxide   
 toluene         
 water           
 ethanol         
 
»Aabc  <-- checking to see that one of the numeric arrays is also
           set correctly.
Aabc =
 
   1.0e+03 *
 
    0.0142    2.9488   -0.0446
    0.0140    2.2924   -0.0279
    0.0147    2.9030   -0.1029
    0.0158    4.0961   -0.0718
    0.0139    2.9327   -0.0556
    0.0142    4.2053   -0.1192
    0.0141    2.8254   -0.0427
    0.0142    3.3042   -0.0552
    0.0140    2.5546   -0.0363
    0.0152    3.0083   -0.0865
       NaN       NaN       NaN
       NaN       NaN       NaN
       NaN       NaN       NaN
    0.0169    1.3191   -0.0141
    0.0134    0.6582   -0.0029
       NaN       NaN       NaN
       NaN       NaN       NaN
       NaN       NaN       NaN
    0.0143    3.2424   -0.0472
    0.0165    3.9854   -0.0390
    0.0162    3.4235   -0.0557
 
»

Return to Table of Contents