00 positive Bewertungen00 negative Bewertungen

31 Ansichten17 SeitenC++ for Fem

Dec 20, 2016

© © All Rights Reserved

PDF, TXT oder online auf Scribd lesen

C++ for Fem

© All Rights Reserved

Als PDF, TXT **herunterladen** oder online auf Scribd lesen

31 Ansichten

00 positive Bewertungen00 negative Bewertungen

C++ for Fem

© All Rights Reserved

Als PDF, TXT **herunterladen** oder online auf Scribd lesen

Sie sind auf Seite 1von 17

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

0 1994 by John Wiley & Sons, Ltd.

~

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

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

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

4

Swap Contents of Temporary Matrix #2 with D

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

(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

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

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

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.

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

1

B.MAdd

1

A.operalor =

Matrix

3928

G. W. ZEGLINSKI ET AL.

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

Function Name

Purpose

NodeList

NodePoints

MaterialType

Results

GetLocalStiff

GetLocalStimnGlobal

Posthocess

GetRow

GetCol

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

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

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

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

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 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

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

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

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

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

&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

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

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.

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.

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.

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

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" ;

/ / For simplicity of the example, the DOF is read in

INPUT>>NumMaterial>>NumNodes>>NumLoads>>Nu~lements>>DOF;

/ / 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.

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.

## Viel mehr als nur Dokumente.

Entdecken, was Scribd alles zu bieten hat, inklusive Bücher und Hörbücher von großen Verlagen.

Jederzeit kündbar.