Sie sind auf Seite 1von 17

INTERNATIONALJOURNAL FOR NUMERICAL METHODS IN ENGINEERING,VOL,

37, 3921 -3937

OBJECT ORIENTED MATRIX CLASSES FOR USE IN


A FINITE ELEMENT CODE USING C + +
GORDON W. ZEGLINSKI AND RAY P. S. HAN

Department of Mechanical and Industrial Engineering, Uniuersity of Manitoba, Winnipeg, Manitoba, Canada, R3T ZN2
PETER AlTCHlSON

Department of Applied Mathematics, University of Manitoba, Winnipeg, Manitoba, Canada, R3T 2NZ

SUMMARY
This paper presents a new method of writing finite element programs using the programming approach
known as object oriented programming (OOP). More specifically, the C + + language is used to illustrate
the key OOP concepts. In addition to the OOP finite element examples, a detailed discussion of OOP
techniques in the creation of a generalized matrix library is presented. The C + + language is used in this
paper because it is more suited to numerical programs than a pure OOP language such as Smalltalk. The
efficiency, flexibility and maintainability of the C + + program are shown to be superior to a comparable
version written in a non-OOP language, such as FORTRAN. The matrix library contains a number of
matrix objects that are useful for specific types of matrix related problems. Different sparse storage schemes
are implemented for each different type of matrix. A large number of functions are provided for each matrix
type in order to implement many common matrix operations. In applications, the OOP paradigm allows the
functions to be used in a very simple way that is common to all the matrix types. The sample finite element
code included in this paper is primarily intended to illustrate the key concepts of OOP style. This paper
explains how to set up a finite element hierarchy, material hierarchy and how to integrate this with the
matrix hierarchy (library). Thus, a completely object oriented finite element program can be written.

INTRODUCTION
There has been much work done and published in the field of matrix research.' For full matrix
computations, packages such as IMSL and EISPAC have become standards, and the algorithms
in these packages can be obtained from a number of sources.2 Other popular packages include
Math.h, Matrix.h and Linpack.h from Rogue Wave. However, for sparse matrices, there are no
generalized packages available because of the vast variety of storage schemes that are used.
Instead, only algorithms and specialized routines are generally a ~ a i l a b l e An
. ~ object oriented
approach to a matrix package can overcome the difficulties arising out of the use of different
storage schemes. The very nature of the finite element method makes it ideal to implement finite
element code in an object oriented a p p r ~ a c hThe
. ~ finite element method typically generates large
sparse matrices. Thus, it would seem reasonable to combine the object oriented matrix and object
oriented finite element packages so that the benefits of a completely object oriented approach to
the finite element method can be obtained. Another ideal application of the object oriented
approach is the integration of finite element and graphics program^.^
The purpose of this work is to describe a matrix class library that will serve as the base from
which the matrix routines required in the OOP approach to finite element modelling can be

CCC 0029-598 1/94/22392 1 17$9.00


0 1994 by John Wiley & Sons, Ltd.
~

Received 24 February 1993


Revised 30 December 1993

3922

G . W. ZEGLlNSKl ET AL.

developed quickly and effectively. This work is focused on the programming techniques used to
develop the matrix library and further details can be found in Reference 6. For more introductory
concepts of OOP, the reader is referred to Reference 7, and in its companion paper (Reference 8)
several applications of the OOP paradigm for scientific codes are reported.
There are many advantages to OOP but many OOP languages carry too much overhead. This
overhead makes them unusable for fast, efficient numerical programming. C + + combines the
benefits of O O P with the speed of traditional C. The advantages of this language over C and
FORTRAN are easy program maintenance, greater flexibility, and generally more readable code.
The readability of C + + code is generally greater than that of FORTRAN code because C + +
allows the functionality of the operators to be extended for new data types. Thus, C + + code can
be written so that it has an intuitive look to it. For example, the addition operator could mean
sum when used with numbers or matrices but it could mean append when used with character
strings.
To this date, there has been no work done that applies C + + approach to OOP for
a generalized sparse and full matrix class designs in finite element programming. Most past work
in this field is based on FORTRAN 77, which was the best choice for programming applications
that required intensive numerical computations. However today, C + + is a more flexible and
powerful language. It draws its power from two areas. First, it has all of the power features
associated with C, the most important of which for the matrix class is the true dynamic memory
allocation. Second, it has all the essential components of a pure OOP language, which allows data
abstraction and inheritance to be performed, the two key concepts used in the matrix hierarchy.
In certain situations, a traditional C or FORTRAN code can be faster than the equivalent C + +
code but the resulting speed differences are not significant when matrices are involved, such as in
solving a system of equations. Also, there are some minor overheads in employing the OOP
features of C + + and they arise from the use of pointers to call virtual functions which cannot be
called directly. For most practical purposes, these overheads are almost negligible.
THE PURPOSE O F THE MATRIX CLASS
The class structure is defined so that additional types of matrices can be easily added to the
structure as the library is further developed. Initially, several types of matrices are coded into the
class, including general sparse matrices, banded matrices, symmetric matrices and full matrices.
The different matrix types are capable of being intermixed in matrix operations involving three or
more matrices. The classes contain routines that are able to solve sets of linear equations, evaluate
determinants and compute eigenvalues, along with a comprehensive set of routines to perform the
usual basic matrix operations for each of the matrix types. These routines are optimized to take
advantage of the special structure of each of the included matrix types.
ADVANTAGES OF THE OBJECT ORIENTED MATRIX CLASS
The major advantage of the matrix class is that it allows mathematical expressions to be easily
translated into the program because it isolates the complexities of the matrixs data structure and
the computational routines from the rest of the program. This isolation and grouping of data
structures and routines is called encapsulation. Thus, the programmer can concentrate on the
specific application code instead of the matrixs data structure. As a result of the encapsulation
and data abstraction, a properly written finite element program that utilizes this matrix class can
easily switch matrix storage techniques without requiring major sections of the finite element
code to be rewritten. This means that when new more efficient matrix storage structures and

FINITE ELEMENT CODE USING C +

3923

faster algorithms are added to the class, an application that uses this class could easily and
quickly be converted to use these new routines.
The section of the finite element code, known as the j n i t e element engine requires the same
operations to be performed regardless of the finite element type. Even in FORTRAN, the code
was written in an O O P style. However, because FORTRAN is not an OOP language, the O O P
techniques have to be accomplished using a bulky series of ifstatements. This matrix class would
allow the finite element engine to be written cleanly such that additional element types, or
different matrix types could easily be used in the program without changing a single line of code
in the engine.
The following is a sample of the type of expression that can be programmed using this class
library;
A = B x ~ x ( CD
+)xE
where A, B, C,D and E are matrices of any type defined in the library. This cannot be done in
a non-OOP language that does not include matrix classes. The user is limited because no new
types of matrix structure can be added (by the user), an important feature when dealing with
sparse matrices because the storage scheme used is often optimized for the problem that is being
solved. Thus, a non-OOP language that has some matrix capability would place quite a severe
restriction on the user which is absent in an OOP paradigm.

CLASS DESIGN
Figure 1 shows the matrix class hierarchy. By convention, the arrows point from the derived class
to its base. The structure of the diagram is that the objects become more specific in their definition
as one moves down the tree. The lowest object at the end of each arrow is a useable matrix type.
Each box represents a matrix object. The dashed boxes represent abstract classes. Because the
abstract classes define the structure of the hierarchy, they will be discussed in greater depth than
the other classes.

I TriMatnx I

Figure 1. A matrix class hierarchy

3924

G. W. ZEGLlNSKl ET A L

MatrixBase

This is the base class for the entire hierarchy. Thus, it must be carefully designed so as to
provide platform independence, easy expansion and maximum efficiency. Each of these desired
qualities will be explored individually.
Platform independence is desired so that the source code can easily be carried across different
computer architectures and different C + compilers. The first requirement is fairly obvious, the
code should only use the standard C + + function and keywords. The second requirement is not
as clear cut. When a matrix operator performs its operation, it must return the results to the rest
of the program. In general, it should not be allowed to change any of the matrices it is operating
on. Thus, temporary matrices must be returned. Initially, it may seem reasonable to allow the
compiler to handle this. However, the class hierarchy maintains the temporary matrices because
the order of the creation and deletion of temporaries are not standard across compilers and
efficiency can be gained this way. To better understand the need for temporaries consider the
matrix equation
D =(A + B ) x ~ x C

The execution of this equation is illustrated in Figure 2. First, the matrix addition operator is
called. This operator creates the first temporary matrix. The results of the addition operation are
stored in this temporary matrix. Next, the matrix to scalar multiplication operator is called.
Because a temporary matrix is being multiplied by a scalar, a new temporary is not needed. Next,
the matrix multiplication operator is executed. This operator creates the second temporary
matrix to store the results of the operation. When the operation is completed, the first temporary
matrix is deleted. Finally, the assignment operator is called. Because the assignment is from
a temporary matrix, this operator swaps the contents of the two matrices data structures and
deletes the second temporary matrix. The matrixs data structure consists of only a few pointers
and a few integers. In this way, the memory that was held by matrix D is freed and only a few
bytes have to be copied instead of several kilobytes.
Expandability and reusability are among the primary goals of OOP. This hierarchy has been
designed to allow additional matrix type to be easily added. The abstract base class MatrixBase
defines the primary characteristics (functions) that all matrices must provide. It defines all the
standard C + + operators ( + , - ,*, /, * = , / =, + = , - =). These operators are responsible for
the creation and deletion of temporary matrices. The actual operations are done in the member
D = ( A +a)x 3 x C

4
A + B d Temporary Matrix #I

Temporary Matrix # I

+Temporary Matrix

#I

, 4
Temporary Matrix #I

xC

Temporary Matrix #2

Delete Temporary Matrix # I

4
Swap Contents of Temporary Matrix #2 with D

Delete Temporary Matrix #2

Figure 2. Order of execution

FINITE ELEMENT CODE USING C +

3925

functions MMul, MAdd, MSub, CMul, CDiv. Thus, to add a matrix type to this hierarchy, the
programmer must define the appropriate member functions and need not worry about temporary
matrices. These member functions will be discussed later when the class hierarchy is explained in
greater details.
Maximum efficiency is of key concern to numerical routines. Maximum efficiency in this case
refers to minimum computational time. It is possible to write the class hierarchy so that generic
routines can be used to perform multiplication, division, LU decomposition, etc. However, this
would be terribly inefficient. Therefore, each matrix type is allowed to use its own optimized
routines to perform the various tasks. To allow for inter-type operations, a set of generalized
routines has been provided. Also, to improve speed for certain types of operations, both row and
column based matrix types have been implemented where applicable.
All matrix types must have a minimum set of associated functions which can be broken up into
the several categories. These functions allow different matrix types to interact and by defining
these functions, a new matrix type can easily be added. Figure 3 shows these categories and
functions.
SparseBase

This abstract class adds a set of functions unique to sparse matrices, to the functions that are
inherited from MatrixBase. These functions are designed so that the arithmetic between the

Purpose

Fuactioa Name

Basic mathematical functions:


(multiplication, &vision, addition, subtraction)
Assignment operator
Identify matrix type
Create temporary matrix
Get a value from a cell
Put a value to a cell
Create an identity matrix
Get a row from the matrix
Get a column from the mabix
Replace a row in the matrix with the supplied vector
Replace a column in the matrix with the supplied vector
Transpose the matrix.
Inverse the matrix
Extract a sub matrix
Insert a sub matrix

MMul, CMul, CDiv, MAdd MSubl

operator =
MatrixType
CreateTmpMat
GetVal, QGetVa12
PutVal, QPutVal
idmt
GetRow
GetCol
PutRow
PutCo1
hanS
inv
GetSubMat
PutSubMat

' M M d is used for matrix multiplication. CMul is used for scalar to matrix multiplication. MAdd and
MSub are matrix addition and mamx subraction respectively.
.
'GetVal is a full error checking routine. QGetVal performs no error checking. Thus, QGetVal should
only be used after the program has been thoroughly debugged. The same naming convention is used by
PutVal and QPutVal.
Figure 3. Mandatory matrix functions

3926

G . W. ZEGLLNSKI ET AL.

various sparse types can be done as efficiently as possible. They allow a generic, matrix type
independent interface to be used to query the sparse matrix for its elements in a very efficient
manner.
LinkedBase

This abstract class defines all the necessary functions to manipulate the linked list data
structure. The linked list structure holds the non-zero terms of the matrix in a contiguous manner.
It uses the concept of minor and major indices. A major index is the index by which the data is
stored. The minor index is the remaining index. For example, in a row based list structure, the row
index is the major index and the column index is the minor index. This allows both row and
column based list structures to be easily defined. Both the value of the term and its minor index
are stored. A list of the elements is used to chain all the elements in a given major together. To
know the start of the list for each major, an array is used to hold this data. Both row and column
based structures are useful because for certain applications, it is far more efficient to access the
matrix along its major index.
Figure 4 illustrates a typical sparse matrix for which a matrix derived from this class would be
used. The elements with an X in them are the non-zero elements. The rest are zero elements. There
is no useable bandwidth for this type of matrix.
BandedBase

This abstract class defines all the necessary functions to manipulate banded matrices which are
stored in the usual banded storage system. As in the linked list system, this class uses the concept
of minor and major to create derived row and column based storage schemes. The banded storage
structure requires less data per element to be stored than the linked list structure because for the
banded scheme, only the value of the element is stored. Hence, for matrices with dense bands, this
storage system is far better than the linked list storage system. Figure 5 depicts an ideal banded
matrix for which a matrix derived from this class would be used. This is a typical densely
populated banded matrix.
TriMatrix

There are many features common to all triangular matrices. This abstract class creates
functions necessary to maintain this type of structure. From this class, lower triangular matrices,
upper triangular matrices, symmetric matrices and a matrix which store the U'U decomposition
are derived.
X

X
X

,Y

x
X

Figure 4. A typical sparse matrix

FINITE ELEMENT CODE USING C + +

3927

x x x
x x x x
x x x x x

x x x x x
X

X X X

x x x x x

x x x x
x x x
Figure 5. An ideal banded matrix

INNER WORKING OF THE HIERARCHY


The execution of the following equation will be flow-charted in Figure 6 so that a better
understanding of how the hierarchy works can be obtained. For this example, matrices A, B and
C are of the Matrix class, a storage scheme for full matrices.
A=B+C

Figure 6 illustrates several interesting points. The first point is that the function that performs the
matrix arithmetic is a member function of the matrix object that is at the left-hand side of the
operator. The temporary matrix is created by a member function of the object that is at the
left-hand side of the operator. The assignment operator is a member function of the matrix object
into which it is placing the values.

THE FINITE ELEMENT ENGINE


Now that some of the basic principles of OOP have been explained using the matrix class
hierarchy, the design of an OOP finite element engine can be discussed. In this section, the code
based on the conventional FORTRAN language will be compared with a new engine written in
C + +. But first, a sample hierarchy for a finite element class will be presented because in OOP,
the class hierarchy is the most important aspect of the code design.

MatrixBase :: operator +

1
B.CreateTempMat

(Create Temporary Matrix)

1
B.MAdd

(Add Band C Store Result in Temporary Matrix)

1
A.operalor =

Matrix

(Copy Data from Temporary Matrix into A)

(Destroy Temporaq Mauix)

Figure 6. Order of execution for the sample equation

3928

G. W. ZEGLINSKI ET AL.

The finite element hierarchy

Figure 7 shows a very simple finite element hierarchy. This hierarchy is really too simple for
a real finite element program but it does clearly illustrate the basic concepts that will be
elaborated upon later. As with the matrix classes, the first abstract class defines the overall
structure of the hierarchy. In this case, this is the FiniteElement class. This class contains the data
members and member functions shown in Figure 8. In addition to the element hierarchy,
a material hierarchy will also be described. These two hierarchies, when combined with the matrix
hierarchy, will form the base for a simple FE program. The source code necessary to define the
element hierarchy is listed in Figure 9. The code in Figure 9 defines the C + + class structure
illustrated in Figure 7. This code would typically be placed in a header file that would be included
into other source code files that define the function bodies and the rest of the program. This code
will now be explained.

______
1 --

FiniteElement

Figure 7. A simple finite element hierarchy

Function Name

Purpose

NodeList

This variable points to the list of nodes in the global

NodePoints
MaterialType
Results
GetLocalStiff
GetLocalStimnGlobal
Posthocess
GetRow
GetCol

system. This is a static variable, meaning that it is


shared by all instances of the finite elements.
This variable points to the list of nodes present in the
element. This is not a static variable. Thus, each
instand has its own unique variable.
This variable points to the material fiom which the
element is made. This is not a static variable.
This variable point to the matrix in which the result for
the solution of the global stiffness matrix is stored.
This function returns a full matrix containing the
stiffness matrix in local coordinate.
This function returns a sparse matrix containing the
stifmess matrix in global coordinates.
This function post-processes the solution.
Returns the row in which the local stifmess matrix
starts to be inserted into the global stifhess matrix at.
Returns the column in which the local stiffness matrix
starts to be inserted into the global stifmess matrix at.

An instance is the O O P terminology for a variable. For example in the statement integer i, i is an

instance of the object integer.


Figure 8. Variables definition for the sample C + + code

FINITE ELEMENT CODE USING C + t

1
2
3
4
5
6
1
8

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
21
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

class FiniteElementt
protected:
static Matrix *NodeList;
static Material **Materials;
int INodePoints;
int MaterialType;
pub1 ic :
FiniteElement(int NodeIndex);
FiniteElement(int NumberNodalPoints);
FiniteElement(ifstream &IN);
virtual -FiniteElement( ) ;
virtual MatrixBaseh GetLocalStiff()=O;
virtual MatrixBaseh GetLocalStiffInGlobal(int DOF)=O;
virtual PostProcess(MatrixBase& sol, ofstream hOut)=O;
virtual GetRow(int DOF)=O;
virtual GetCol (int DOF)=O;
static void SetNodeListStart(Matrix *NL);
static void SetMaterialStart(Materia1 **Mat);
1;
class Truss-2D:public FiniteElement(
public:
Truss-ZD(int *NodeIndex);
Trrus-2D(ifstream &IN);
-Truss_2D ( ) ;

MatrixBaseh GetLocalStiffO;
MatrixBaseh GetLocalStiffInGlobal(int D O F ) ;
PostProcess(MatrixBase& s o l , ofstream &Out);
GetRow(int DOF);
GetCol (int DOF);
1;
class Truss-3D:public FiniteElementl
public:
Truss_3D(int NodeIndex);
Truss_3D(ifstream CIN) ;
-Truss_3D ( 1 ;

MatrixBaseC GetLocalStiffO;
MatrixBaseS GetLocalStiffInGlobal(int DOF);
PostProcess(MatrixBase& s o l , ofstream &Out);
GetRow (int DOF);
GetCol (int DOF);

44

45
46
41
48

49
50
51
52
53
54
55
56
57

3929

t;
class P1ate:public FiniteElementi
public:
Plate(int NodeIndex);
Plate (ifstream 6IN);
-Plate ( ) ;
MatrixBase& GetLocalStiff 0 ;
MatrixBase& GetLocalStiffInGlobal(int D O F ) ;
PostProcess(MatrixBase& so1,ofstream &Out);
GetRow (int DOF);
GetCol (int DOF) ;

I;
Figure 9. Source code for the finite element hierarchy

The keywords protected and public found in lines 3 and 8 are called the access specifiers.
They control who is allowed access to the member data and functions immediately following
them. On line 23, the keyword public is now referred to as an access modifer. It adjusts the access
of the members of its parent class when they are being accessed through a child class. The parent

3930

G. W.ZEGLINSKI ET AL.

class in the finite element hierarchy is the class FiniteElement. The child class is any class that is
derived from it. The static keyword found in line 4 is used to indicate that the variable will be
shared among all instances of the classes derived from the FiniteElement. This saves space
because only one node list is needed for the problem and all instances of elements need access to
this one list. Thus only one copy of the pointer exists.
Lines 9-11 are constructors. Constructors are called when a new instance of an object is
created. In this example, three constructors are defined. The first copies its argument into the
NodeIndex variable, the second allocates storage space for the elements node point list, and the
last one reads the data in from an input stream.
The virtual keyword found in lines 12 and 14 states that the member function is a virtual
member function. A virtual member function is the means by which polymorphism is achieved.
This mechanism allows the appropriate version of the member function to be used regardless of
the circumstances in which it is being called. In the matrix hierarchy, virtual functions are used to
implement the multiplication routines, solvers, and other major functions. In line 12, the member
function is a virtual destructor. Virtual destructors insure that the object is being cleaned up
properly when polymorphism is being used. The = 0 keyword appears at the end of line 14. When
combined with the virtual keyword,this means that the function is a pure virtual member
function. Pure virtual member functions have no body. Thus, they must be redefined in derived
classes as either pure virtual or as a regular virtual function with a body. The virtual keyword has
been omitted in all derived classes because the member functions that are defined as virtual in the
parent class automatically become virtual in the child class.
Line 22 shows the syntax for the process of deriving a class from another class. In this line, the
Truss-2-D object is being derived from the FiniteElement object. The bodies of these member
functions would contain the code necessary to fill in the stiffness matrix, calculate its entries, as
well as other basic tasks as described previously. The codes for these functions would be very
similar to that of a non-OOP program4 and thus do not warrant an in-depth discussion.
Figure 10 shows a sample material hierarchy. It contains only two metals and combines the
geometric and material properties into a single object. This simplified design is only for illustrative purposes. In a professional package, the hierarchy would be expanded to include many more
properties and more materials, and therefore, combining both geometric and material properties
into a single object would not be appropriate. Figure 11 shows the source code necessary to
set-up this hierarchy.
In this hierarchy, a material is a combination of the metal and its geometry. The two material
types defined here are a steel bar of rectangular cross section and an aluminum bar of circular
cross section. Using these two hierarchies, the material property and the element type have been
clearly separated into two sections. If a new element is added, a new class is derived. Similarly, if
a new material is added, a new material is derived. Thus, there is no overlap in the coding and
there is no need to change the other sections when one section is modified.

------1
I

Material

Figure 10. A sample material hierarchy

FINITE ELEMENT CODE USING Ct t


L

class Material1

2
3
4
5

public:
Material ( 1 ;
virtual float GetElasticityO=O;
virutal float GetArea ( ) =O;
virtual float GetMomentOfInertiaO=O;

7
8
9

3931

1;

10

11
12
13

14
15
16
17
18
19
20
21

class Stee1:public Material(


static float E;
float Height, Width;
pub1 ic :
Steel(f1oat height, float width);
Steel (ifstream &IN);
float GetElasticityO (return E;}
float GetAreaO (return Height*Width;)
float GetMomentOfInertiaO (return Widthfpow(Height,3)/12.0;)

22

23

24
25
26

27
28
29
30
31
32
33
34
35
36
37

1;
class A1uminum:public Material(
static float E;
static pi;
float Diameter;
public:
Aluminum(f1oat diameter);
Aluminum(ifstseam 6IN);
float GetElasticityO (return E;}
float GetAreaO (return pifDiameterfDiameter/4.0;)
float GetMomentOfInertiaO (return pifpow(Diameter/2.0,4)/4.0;)
1;

Figure 11. Source code for the material hierarchy

The FORTRAN finite element engine

Figure 12 shows a section of code from a FORTRAN finite element program. Lines 1-25
represent the section of code that has been referred to as the finite element engine. The rest of the
code is the subroutine that assembles the global stiffness matrix. The finite element engine, in this
program, performs the following tasks: (1) formulates the local stiffness matrices, (2) assembles the
global stiffness matrix, (3) reads in the load matrix from a data file for each loading case, (4) solves
the system of equation and ( 5 ) post-processes the solution.
The assemb subroutine first loops through the group of elements. Each group of elements
shares the same material. Then it loops through the elements in the group to create the local
stiffness matrix. Lines 62-76 contain a series of if statements which test to determine the element
type. Based upon the outcome of the tests, a specific subroutine is called to generate the local
stiffness matrix. Adding a new element to this program would require additional if tests to be
placed not only in this routine, but also in several other routines that provide this routine with
some of its data. Overall, many new if tests have to be added to the whole program to add a new
element. In addition, is should be noted that the matrix storage system for the program is fixed. It
cannot be changed without changing the section of code that has been rererred to as the finite
element engine.

3932

G . W.ZEGLlNSKl ET AL.

call stiff
(a(P1nods ) , a(Pid
) , a(Pcoord ) , a(Pmatno
),
a (pprops ) , a (Pstfloc), a (Peltrig), a (Pnelempg),
a (Piposek))
call assemb
+
(a(P1nods ) , a(Pid
) , a(Pstfloc), a(Pe1trig) ,
a (Pmaxa ) , a (Pgstif 1 , a (Pnelempg),a (Piposek) ,
a(Pmaxdof))

6
7

9
10
11
12
13
14
15
16
17
18
19

do iload=l,nload
read (input,+ ) nlodno,nlodel
call load
(a(Plnods),a (Pid) ,a (Pcoord) ,a(Peltrig1,
a(Prhs) ,a(Pfea ),a(Pmaxdof),a(Pnelempg))
call s k y
(a(Pgstif ) , a(Prhs ) , a(Pmaxa ) ,neq,nsizg,iload,2)
call wrtdis
+
(a(Pid
) , a (Pcoord), a (Prhs 1, a (Pdisnod), a (Pmaxdof )
call intfor (a(Pid),a (Plnods),a{Pfea), a (Pstfloc),a (Peltrig),
a(Pdisnod),a(Pmaxdof), a(Pnelempg),a(Piposek))
call react (a(Pid),a(Plnods),a(Pfea),a(Pstfloc),a(Peltrig),
+
a (Pdisnod), a (Pmaxdof), a (Pnelempg),a (Piposek)
end do

+
+

20

21
22
23
24
25
26
27
28
29
30
31
32
33

C++++++++l+++l++++++++++++~l+l+l+++++~~++++++++lll++~+++l+++++++l+~++

subroutine assemb
(hods,id,stfloc,eltrig,maxa,stifg1,nelempg.iposek,maxdof)

c subroutine to assemble the global stiffness matrix


C

implicit real+8(a-h,o-z)
include 'contro1.cmn'
include 'ios.cmn'

34
35
36
37

38

39
40
42

54

55
56

57
58
59
60
61
62

63
64

dimension lnods(nelem,l),id(npoin,l),stfloc(l),iposek(l),
eltrig(nelem,1) ,nelempg(ngrp,1 )

dimension rotate(l2,12),dclstf(12,12),rotinv(12,12),
dpstmt (12,121,stfelg(12,12),lm(12)
dimension stifgl(l), maxa(1),maxdof (1)

41

43
44
45
46
47
48
49
50
51
52
53

C
C

do isizg=l,nsizg
stifgl(isizg)=O.O
end do
C

do igrp=l,ngrp
call elematt(nelempg1
do ielem=elembgn,elemend
idof=O
do inode=l,nnode
node =lnods (ielem,inode)
do iid=l,maxdof(node)
idof=idoftl
lm(idof)=id (node,iposid (iid))
end do
end do
istpos=iposek( elem)
if (istrtp.eq.1 then
call getastif stfelg,stfloc(istpos),nsizk)
nkrot=nid*2

Figure 12. (continued)

FINITE ELEMENT CODE USING C +

65
66
67
68
69
70

71
72
73
74
75
76
71
78
I9
80
81
82
83
84
85
86

3933

else
if (istrtp.eq.2)then
call rotaZ(ielem,eltrig,rotate)
elseif(istrtp.eq.3)then
call rota3 (ielem,eltrig,rotate)
elseif(istrtp.eq.4)then
call rota3(ielem,eltrig,rotate)
elseif(istrtp.eq.5)then
call rota5 (ielem,eltrig,rotate)
elseif ( istrtp eq.6)then
call rota6(ielem,eltrig,rotate)
end if

call getastif (dclstf,stfloc(istpos),nsizk)


nkrot=nidf2
call mult
(dclstf,rotate,dpstmt,
12,12,12,nsizk,nsizk,nkrot
call trans (rotate.rotinv,12,12,nsizk,nkrot)
call mult
(rotinv,dpstmt,stfelg,lZ, 12,12,nkrot,nsizk,nkrot
end if

07

88
89
90
91
92
93
94
95
96
91
98
99
100
101
102
103
104
105
106

The C +

do irow=l,nkrot
idlin=lm(irow)
if ( idlin ne 0 ) then
do ikol=l,nkrot
idkol=lm(ikol)
if(idkol.ne.0.and.idlin.le.idkol)then
iadres=maxa(idkol)+idkol-idlin
stifgl (iadres)=stifgl (iadres)+stfelg (irow,ikol)
end if
end do
end if
end do

. .

end do
end do
return

+ Jinite element engine

Figure 13 lists the code for a C + + finite element engine. To make the comparison fair, this
routine will perform the same tasks as the FORTRAN routine. It is obvious that the C+ +
version of the code is much easier to read but the other advantages cannot easily be seen without
further explanations.
The first advantage is that the type of matrix being used to store the global stiffness matrix is
not defined in the routine. The routine is passed the matrix via an argument. The advantage of
this approach is that different matrix types could be used, and this permits the best storage system
and the most optimized solver to be employed for the problem. For example, for a well-posed
physical problem, its global stiffness matrix is usually well conditioned and hence, a simple solver
that does not require pivoting could be invoked. However, for a problem that results in a nearly
singular matrix, a matrix type that possesses the slower and more cumbersome pivoting solver
would be needed for solution.

3934

G. W. ZEGLINSKI ET A L
1

2
3
4
5

void FE-Engine(int NumberElements, FiniteElement **Elements, MatrixBase


&Globalstiff, MatrixBase dSolution, int NumberLoadings, int Globalsize) 1
int i,j;
LinkedRow LoadMatrix(GlobalSize,l); / / create column matrix
for(i=O;i<NumberElements;i++) / / Loop through all the elements
Globalstiff ( (Elements+i)->StartRow(),
(Elements+i')->StartCol()) <<
*(Elements+i)->GetLocalStiffInGlobal();

6
7
8
9

10

Constrain(Globa1Stiff); / / called function to apply constraints


for(i=O;i<NumberLoadings;i++){
LoadMatrix=GetLoad(i);
/ / return load matrix from file
Solution=GlobalStiff.Solve(LoadMatrix);
//solve the
//equations
for(j=O;j<NumberElements;j++)
t(Elements+j)->PostProcess(Solution,OutputFile);
/ / Post-proces the
//solution
1

11
12
13
14
15
16
17

18
19
20

21

22

Figure 13. The C f + finite element engine

The second advantage is that the code is clearly broken into sections. To add a new element
type, a new element object is derived from the FiniteElement class. This new object would then
define the member function discussed in the FiniteElement hierarchy section outlined previously.
The code and data for that element are all contained within its object (class). This makes it much
easier for programmers to develop and maintain the code.

A SIMPLE C + + FINITE ELEMENT PROGRAM

As discussed in the previous section, the C + version of the finite element engine is much
simpler to handle and maintain compared to the corresponding FORTRAN version. It does not
however, illustrate how the data is entered into the program or the flow of the overall program.
To do this, a simple finite element program will be necessary. This program will be designed
around a rather crude but functional data entry routine. This routine will read data from a file
and then construct the necessary objects. The code is shown in Figure 14 and is for a relatively
simple example. Excluded from the code are the basic routines that make up the object
themselves. In a commercial package, the post-processing would include graphical information,
in addition to the file output. Again, this is where OOP techniques excel.' To add this capability
to the program, an additional member function to perform this task would be inserted into the
finite element hierarchy. This function would be called for each element, along with the postprocessing. The overall finite element program can be broken into the following distinct sections.

The elements and materials

These sections of the program are completely contained inside the FiniteElement hierarchy and
the Material hierarchy. They are isolated from the rest of the program so that any changes made
to them do not effect the code in this section. Elements are added by creating new objects.

FINITE ELEMENT CODE USING C +

1
2
3
4
5
6

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
21
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

/ / Output file f o r PostProcessing


of s tseam OUPUT ("outputfile dat" ) ;

int main0 (
int NumMaterial, NumNodes, NumElements, NumLoads;
int i, type, DOF;
//Space to store pointers to the constructed elements
FiniteElement * + Elementstorage;
//Space to store pointers to the constructed materials
Material + * Materialstorage;
//Space to store pointers to the constructed node points
Matrix
Nodestorage;
//Open the input file
i fs tream INPUT ( " inputfile dat" ;

/ / Read in the Number of Materials, Nodes, Loads, and Elements


/ / For simplicity of the example, the DOF is read in
INPUT>>NumMaterial>>NumNodes>>NumLoads>>Nu~lements>>DOF;

//Read in the Nodes


/ / 3 co-ordinates per node
NodeStorage=new Matrix INumNodes];
for(i=O;i<NumNodes;i++)
/ / a 1x3 matrix to hold the co-ordinates
NodeStorage[il=Matrix(l, 3,INPUT);
//Read in the Materials
for (i=O;i<NumMaterial;i++)(
INPUT>>Type;
switch (Type1I
case 1:
MaterialStorage[i]=new Steel(1NPUT);
break;
case 2:
MaterialStorage[i]=new Aluminum(1NPUT);

I
//Read in the Elements
1
for (i=O;i<NumElements;i++)
INPUT>>Type;
switch (Type)I
case 1:
ElementStorage[i]=new Truss-ZD INPUT);
brea k;
case 2:
ElementStorage[i]=new Truss-3D INPUT);
break;
case 3 :
ElementStorage[i]=new Plate(INPUT1;
1
1
//create a sparse matrix to hold the global stiffness matrix
//using a LU decomposition solver without pivioting
LinkedLU StiffMat(NumNodes*DOF,NumNodes*DOF,3 ) ;
//create a full matrix to hold the solution
Matrix Sol (NUmNodes*DOF,1);
FiniteElement::SetNodeListStart(NodeStorage);
FiniteElement::SetMaterialStart(MaterialStorage);
FE-Engine(NumElements, Elementstorage, StiffMat, Solution,
NumLoads, NumNodes+DOF);

45

46
47
48
49
50
51
52
53
54
55

~~

56

57
58
59
60

I
Figure 14. Source code for the C + + finite element program

3935

3936

G. W. ZEGLINSKI ET AL.

The matrices

This matrix type is abstracted from the program via the Matrix hierarchy. It allows for the
most efficient storage and solution systems to be applied for the given problem. This is a highly
desirable feature for any general multi-purpose finite element package. As well, the matrix
hierarchy can be used to provide hardware independence so that different types of matrix
hardware, specialized chips to perform matrix math, etc. can be easily incorporated into the
software.
Data input

This section is closely connected with the type of elements and materials present. It translates
the users model into the computational model and therefore, must be changed when additional
elements or materials are added.

The engine

This section of the program uses OOP techniques to insulate it from changes made to the
matrix storage method used, material hierarchy and element hierarchy. This section remains
invariant to any changes.

The post-processing

This section of the program displays the results of the computations. It is also insulated from
changes in the element, material and matrix hierarchies.
DISCUSSION AND CONCLUSIONS
The matrix hierarchy detailed in this report is designed to be easily expandable, efficient and
platform independent. This has been illustrated by discussing the abstract objects that are so
important in the definition of the hierarchy. As well, several examples have been used to illustrate
how the hierarchy works and interacts within a program. For maximum efficiency in a variety of
applications, several matrix types have been written. These include types of general sparse
matrices, banded matrices, full matrices, full symmetric matrices, upper triangular matrices and
lower triangular matrices.
It has been shown by the way of code excerpts, that the C + + version of the finite element
engine is much better than the FORTRAN version. The C + + code is more readable, maintainable and flexible in that it is much easier to add new element types. Ultimately, it translates to less
time being spent in performing these tasks and this implies lower cost for program development.
As well, the C + + code can use the matrix class hierarchy detailed in this paper so that the most
efficient matrix type is used to store and solve the system of global stiffness equations.

ACKNOWLEDGEMENT

The funding for this research has been provided by the National Science and Engineering
Research Council of Canada.

FINITE ELEMENT CODE USING C +

3937

REFERENCES
1. G. H. Golub and C. F. Van Loan, Matrix Computations, The John Hopkins University Press, Baltimore, 1989.
2. W. H. Press, S. A. Taukolsky, B. P. Flannery and W. T. Vetterling, Numerical Recipes, Cambridge University Press,
Cambridge, 1986.
3. Sergio Pissanetsky, Sparse Matrix Technology, Academic Press, London, 1984.
4. R. I. Mackie, Object oriented programming of the finite element method, Int. j . numer. methods eng., 35,425-436,1992.
5. J. A. Abdalla and C. J. Yoon. Object-oriented finite element and graphics data-translation facility, ASCE. J . Comput.
Civil Eng., 6, 302-322, 1992.
6. G. W. Zeglinski, Object oriented matrix classes for sparse matrices using C +
M.Sc Thesis, University of Manitoba,
Winnipeg, Manitoba, Canada, 1993.

+,

7. T.J. Ross, L. R.Wagner and G. F. Luger, Object oriented programming for scientific codes. I: thoughts and concepts,
ASCE J. Comput. Ciuil Eng., 6, 480496, 1992.
8. T. J. Ross, L. R. Wagner and G . F. Luger, Object oriented programming for scientific codes. 11: examples in C + +,
ASCE J . Comput. Civil Eng., 6,497-514, 1992.