You are on page 1of 160

Analysis of Structures

Book of Examples
2018

University of Duisburg-Essen
Faculty of Engineering
Department of Civil Engineering
Structural Analysis of Plate and Shell Structures

Dr. E. Baeck

8.5.2018
Contents

I Programming with Python 3

1 How to get started with Python 5


1.1 What is Python? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2 Python, Packages, Utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2.1 Installing the Kernel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2.2 Installing the ComType Package . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2.3 Installing the NumPy Package . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.2.4 Installing the SciPy Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.2.5 Creating Python Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.2.6 Python Implementations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.2.6.1 CPython the Reference Implementation . . . . . . . . . . . . . . . . . 11
1.2.6.2 Jython, let’s go Java . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.2.6.3 IronPython, let’s go .Net . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.2.6.4 PyPy, Python to the Square . . . . . . . . . . . . . . . . . . . . . . . 11
1.3 Hello World . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.4 Python Calculator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

2 Basics in Python 15
2.1 Code Convention . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.2 Reserved Words . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.3 Packages and Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
2.3.1 Import of a whole Module or Package . . . . . . . . . . . . . . . . . . . . . . . 16
2.3.2 Import all Names of a Module . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.3.3 Selective Import of Module Names . . . . . . . . . . . . . . . . . . . . . . . . 17
2.3.4 Import with new Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.4 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.4.1 Unary Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.4.2 Arithmetic Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.4.3 Bit Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.4.4 Extended Assign Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.4.5 Manipulating Bits and Hexadecimal Numbering System . . . . . . . . . . . . . 20
2.4.6 Comparison Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.4.7 Membership Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.4.8 Identity Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.5 Print and Output Formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.6 Basic Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

iii
Page iv Analysis of Structures - SS 15

2.7 Code Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25


2.8 Globales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.9 Loop for Repetitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.9.1 The Factorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
2.9.2 Floating Point Precision . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.9.2.1 Description of the Application . . . . . . . . . . . . . . . . . . . . . 30
2.9.2.2 Exercise . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.10 Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.11 Branches for Decisions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.12 Conditional Assignments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.12.1 How to Solve a Quadratic Equation . . . . . . . . . . . . . . . . . . . . . . . . 32
2.12.1.1 A Flow-Chart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.12.1.2 The Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.13 Function Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.13.1 An Abs-Function with Type-Checking . . . . . . . . . . . . . . . . . . . . . . . 35
2.13.2 The Newton-Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2.14 Data Sequences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.14.1 Working with Tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.14.2 Working with Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.14.3 Working with Dictionaries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.15 Error Handling with Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.15.1 Syntax Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.15.2 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
2.15.3 Handling Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
2.15.4 Raise Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
2.16 Random Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.17 Date, Time and Timespan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
2.18 Working with Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
2.18.1 Open a File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
2.18.2 Write Data into a File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
2.18.3 Close a File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
2.18.4 Read Data from a Text File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
2.18.5 A Logger-Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
2.19 OOP with Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.19.1 Some UML Diagrams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
2.19.2 Implementation of Classes in Python . . . . . . . . . . . . . . . . . . . . . . . 55
2.19.2.1 Class Constructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
2.19.2.2 Class Destructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
2.19.3 Implementation of a Time Stack Class . . . . . . . . . . . . . . . . . . . . . . . 57

3 Python Projects 61
3.1 Newton, Step2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
3.2 Profiles, Thin Walled Approach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
3.2.1 A General Base Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
3.2.2 A Node Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69

E. Baeck
CONTENTS Page v

3.2.3 Testing the Node Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70


3.2.4 An Element Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
3.2.5 Testing the Element Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
3.2.6 A General Profile Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
3.2.7 The AList Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
3.2.8 Testing the Profile Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
3.2.9 The U-Profile Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
3.2.10 Testing the UProfile Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
3.2.11 The Profile Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
3.2.12 A Little Profile Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88

II Scripting with Abaqus 91

4 Some Aspects and Introduction 93


4.1 Aspects of the Abaqus GUI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
4.2 The Abaqus CAE Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
4.3 A Modeling Chain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
4.4 A little interactive Warm Up Example . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
4.4.1 Create a Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
4.4.2 Create a Sketch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
4.4.3 Create a Part . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
4.4.4 Create and Assign Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
4.4.5 Create the Instance, Assign the Part . . . . . . . . . . . . . . . . . . . . . . . . 97
4.4.6 Create a Load Step . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
4.4.7 Create Loads and Boundary Conditions . . . . . . . . . . . . . . . . . . . . . . 97
4.4.8 Create the Mesh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
4.4.9 Create a Job and Submit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98

5 Scripts and Examples 99


5.1 3 Trusses Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
5.2 U-Girder Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
5.2.1 System and Automated Analysis . . . . . . . . . . . . . . . . . . . . . . . . . . 106
5.2.2 Scripting and OOP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
5.2.3 Class InputData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
5.2.4 Class ResultData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
5.2.5 Class Base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
5.2.6 Class UGirder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
5.2.7 Run the UGirder Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
5.2.7.1 Results of the Linear Static Step . . . . . . . . . . . . . . . . . . . . 123
5.2.7.2 Results of the Buckling Step . . . . . . . . . . . . . . . . . . . . . . 124
5.2.7.3 Results of the Frequency Step . . . . . . . . . . . . . . . . . . . . . . 126

III Appendix 129

A Some Special Problems 131

8.5.2018
Page vi Analysis of Structures - SS 15

A.1 Modules and Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

B Some Theory 133


B.1 Section Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
B.1.1 The Area of a Profile Section . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
B.1.2 First Moments of an Area . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
B.1.3 Second Moments of an Area . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
B.1.4 Center of Mass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
B.1.5 Moments of Inertia with Respect to the Center of Mass . . . . . . . . . . . . . . 135
B.1.6 Main Axis Transformation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136

C Some Python IDEs 137


C.1 The Aptana - IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
C.2 The PyCharm - IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
C.2.1 General Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
C.2.2 A Hello-Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138

D Conventions 141
D.1 The Java Code Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141

E Parallel Computing 143


E.1 Threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
E.2 A Multi-Processing Pool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
E.2.1 A Single Processor Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
E.2.2 A Multi Processor Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145

F Some Special Abaqus-GUI-Features 147


F.1 Viewport Annotations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
F.1.1 The Legend’s Font Size . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
F.2 Specify View . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149

E. Baeck
CONTENTS Page 1

8.5.2018
Page 2 Analysis of Structures - SS 15

E. Baeck
Part I

Programming with Python

3
1

How to get started with Python

1.1 What is Python?

Python is a functional and object orientated computer language. The language’s


development was started by Guido van Rossum, who was working with the Cen-
trum voor Wiskunde en Informatica (CWI) in Amsterdam Netherlands, see figure
1.1

The name Python has nothing to do with the snake of the same name. The name
Python was taken from the British surreal comedy group Monty Python (see figure
1.2). Because the Monty Python is hard to symbolize onto an icon, the python
snake came into picture and so on all icons and Python symbols today we can see
Figure 1.1: the snake.
Guido van Rossum
The Python language is highly dynamic, so the language is able for example to
create it’s source code by itself during runtime. This fact and it’s highly portability are reasons for it’s
interpreted kind.

So Pyhton code like Java or C# code too is converted


into a socalled bytecode. The bytecode then is executed
on a virtual machine. It’s a program, which can be seen
as virtual processor or an emulator. If such a virtual ma-
chine is available on a platform, the bytecode can be ex-
ecuted without any adaptions.1 With this advantage of
highly portability Python comes with the general disad-
vantage of interpreted languages, the disadvantage of a
really bad performance compared to compiled languages
like FORTRAN or C.
Figure 1.2: Monty Python

1
This is only true, if no platform depended packages like comTypes are used.

5
Page 6 Analysis of Structures - SS 15

1.2 Python, Packages, Utilities

If we start with Python, we should think about the choice of the Python version. Because we will use
some additional Python packages, we should be sure, that this packages are available for the desired
Python version. In the case of our lecture we will select the Python version 2.6, which is properly stable
and furthermore all the needed add-on packages are available.

To start from the beginning, we have to download the following packages for windows first. It is rec-
ommended to download the windows installer version, if available because this is the easiest kind of
installation. The installation procedure should start with the installation of the kernel package.

• python-2.6.4.msi
The installer of the python kernel system 2.6.

• comtypes-0.6.2.win32.exe
The installer of Windows types, which are necessary to use Windows API-calls.

• numpy-1.4.1-win32-superpack-python2.6.exe
The installer of the NumPy package for numerical programming.

• scipy-0.8.0-win32-superpack-python2.6.exe
The installer of the SciPy package for sientific programming.

• matplotlib-0.99.3.win32-py2.6.exe
The installer of the MatPlotLib package. This package we need to get the pylab package.

• pywin32-214.win32-py2.6.exe
The installer of a little nice Python IDE.

1.2.1 Installing the Kernel

The python kernel should be the first package, which is to install, because this installation sets up the
Python base folder. Within this folder you can find the folder Lib, which contents a lot of libraries and
additional packages and besides that a further sub folder called site-packages. Add ons are copied into
this folder by their installers or by the install Python script.

The start screen of the Python installer shows the Python version. You can select, whether the setup
should make Python available for all users or not. After clicking next you’ll get within the second form
the possibility to select the base folder of Python. By default Python uses the folder C:\Python26.
We overwrite the default and select the Windows standard program folder as starting folder, so we write
c:\Programme\Python2623 .

The figures 1.3 and 1.4 show the input forms installing the Python kernel.

1.2.2 Installing the ComType Package

If you want to use the Python language on a Windows system, it’s recommended to install the ComTypes
package. This package will give you a simple access to the Windows resources. It can be understood as
2
The discussed installation was performed on a German system.
3
The installation of newer packages is working in the same way.

E. Baeck
1.2. PYTHON, PACKAGES, UTILITIES Page 7

Figure 1.3: Start Screen of the Python Installer and Choice of Base Folder

Figure 1.4: Selection the Features and Starting the Installation

a wrapper layer, an interface layer for the access to Windows DLL-modules. ComTypes can be a help to
develop a software with a proper Windows look and feel.

The installation of the most Python packages will run very simular to the following installation. The
figures 1.5 show the first and second form of the installation procedure. The first form gives a few
information to the package. The second form is usually used to select the Python version. Each installed
and supported Python version will be listed in the list box of the second form. You can select the desired
Python version and can go on with the installation procedure clicking the next button.

1.2.3 Installing the NumPy Package

NumPy [2] is the fundamental package for scientific computing in Python. It is a Python library that pro-
vides a multidimensional array object, various derived objects (such as masked arrays and matrices), and
an assortment of routines for fast operations on arrays, including mathematical, logical, shape manipula-
tion, sorting, selecting, I/O, discrete Fourier transforms, basic linear algebra, basic statistical operations,
random simulation and much more.

At the core of the NumPy package, is the ndarray object. This encapsulates n-dimensional arrays of

8.5.2018
Page 8 Analysis of Structures - SS 15

Figure 1.5: Start Screen of the Package Installer and Choice of the installed Python Version

homogeneous data types, with many operations being performed in compiled code for performance.4

The installation runs like the installation of the ComTypes package (see figure 1.6).

Figure 1.6: Start Screen of the Package Installer and Choice of the installed Python Version

4
For more details see NumPy User Guide available on the info.server.

E. Baeck
1.2. PYTHON, PACKAGES, UTILITIES Page 9

1.2.4 Installing the SciPy Package

SciPy [3] is a collection of mathematical algorithms and convenience functions built on the Numpy ex-
tension for Python. It adds significant power to the interactive Python session by exposing the user to
high-level commands and classes for the manipulation and visualization of data. With SciPy, an inter-
active Python session becomes a data-processing and system-prototyping environment rivaling sytems
such as Matlab, IDL, Octave, R-Lab, and SciLab.

The additional power of using SciPy within Python, however, is that a powerful programming language
is also available for use in developing sophisticated programs and specialized applications. Scientific
applications written in SciPy benefit from the development of additional modules in numerous niche’s
of the software landscape by developers across the world. Everything from parallel programming to web
and data-base subroutines and classes have been made available to the Python programmer. All of this
power is available in addition to the mathematical libraries in SciPy.5

The installation runs like the installation of the ComTypes package (see figure 1.7).

Figure 1.7: Start Screen of the Package Installer and Choice of the installed Python Version

5
For more details see SciPy Reference Guide available on the info.server.

8.5.2018
Page 10 Analysis of Structures - SS 15

1.2.5 Creating Python Source Code

To create Python sources we need at least a simple text editor like Notepad++ or PSPad6 like for every
computer language. This source files with the standard extension py, like helloworld.py, can be
executed starting the Python interpreter.7
1 c:\pyhton27\python helloworld.py

For Windows there is a lightweigth IDE available called PythonWin. PythonWin looks like an extension
to the MS-Editor Notepad. To create and check small Python scripts, this IDE seems to be ok, because
the overhead we have to overcome is very small compared to really good IDEs.

The installation of PythonWin runs like the installation of the ComTypes package (see figure 1.8).

Figure 1.8: Start Screen of the PythonWin IDE Installer and Choice of the installed Python Version

After having installed the PythonWin IDE it’s recommended to set up a link onto the desktop (see figure
1.9).

Figure 1.9: Creating a Link to the pythonwin.exe

Figure 1.10 shows, how to create a Hello World application in Python and the application’s execution.
Within the editor window, we write the source code. With the start button (black triangle) we can run the
Hello World from the PythonWin. The applications screen output is written into the Interactive Window,
which also is working as a Python console.
6
Notepad++ and PSPad are available on the info.server in /Software/Editors.
7
In this case the Python 2.7 was installed into the Folder c:/Python27.

E. Baeck
1.2. PYTHON, PACKAGES, UTILITIES Page 11

Figure 1.10: Creating and Executing a Pyhton Hello within PythonWin

1.2.6 Python Implementations

1.2.6.1 CPython the Reference Implementation

There is not only one Python implementation available. The original implementation is written in C. It’s
the reference implementation, developed by Guido van Rossum, called CPython too.

1.2.6.2 Jython, let’s go Java

Jython (or JPython) is an implementation of the Python language in Java. The interpreter therefor is
running on a Java environment and is able to use all Java libraries.

1.2.6.3 IronPython, let’s go .Net

IronPython is an implementation for the Common-Language-Infrastructure (CLI), i.e. for the .Net en-
vironment on Windows or for the compatible environment Mono on Linux. IronPython is written in C#
and is available in a CLI language (like C#) as a script language. IronPython is compatilble to CPython’s
version 2.7.

1.2.6.4 PyPy, Python to the Square

PyPy is a Python interpreter, which is implemented using the Python language. It’s used as an experi-
mental environment to develop new features.

8.5.2018
Page 12 Analysis of Structures - SS 15

1.3 Hello World

Like in every computer language there is a Hello World application in Python also possible. We start
dhe PythonWin IDE and create a new file. We save this file as HelloWorld.py. With Ctrl-R the execution
form is shown and the execution mode should be selected (see figure 1.11).

The following available execution modes are available.

• No debugging,
execution without debugging.

• Step-through in the debugger,


the debugger is stated and starts with the first statement.

• Run in the debugger,


the script is started. Execution is only interrupted at the first breakpoint.

• Post-Mortem of unhandled led exceptions,


the debugger is started, if the script crashes with a unhandled exception.

Figure 1.11: Executing the HelloWorld.py Script

If the HelloWorld.py script is executed, the output is written into the Interactive Window, see figure 1.10.

E. Baeck
1.4. PYTHON CALCULATOR Page 13

1.4 Python Calculator

One of Python’s advantages is the feature to execute only one statement within the Python shell. The
Python shell within the PythonWin IDE is given by the Interactive Window, see figure ??.

If we want to calculate the vertical position of a ball thrown up in the air with an initial velocity v0 after
a time t we get from the Newton’s law
1
y(t) = v0 · t − · g · t2 (1.1)
2
So, if we want to calculate the vertical position for an initial velocity v0 = 5m/s after 0,6 seconds, we
can calculate the y(t = 0, 6) with one simple Python call.
1 >>> print 5*0.6 -0.5*9.81*0.6**2
2 1.2342
3 >>>

A second version of the calculation can be performed introducing and using variables as follows. So we
can check every Python command within the Interactive Window.
1 >>> v0 = 5
2 >>> g = 9.81
3 >>> t = 0.6
4 >>> y = v0*t - 0.5*g*t**2
5 >>> print y
6 1.2342
7 >>>

A third version of our calculation of the ball’s height could be a Python script, which we can load and
executed within the PythonWin IDE. To comment the code we insert some comments, which starts with
the # character. Characters at the right side of the # character are ignored by the Python interpreter.

Listing 1.1: Calculation of the Flight Altitude of a Ball

1 # program for computing the height of a ball thrown up in the air


2 v0 = 5 # initial velocity
3 g = 9.81 # acceleration of gravity
4 t = 0.6 # time
5 y = v0*t - 0.5*g*t**2 # vertical position
6 print y # printing the result

8.5.2018
Page 14 Analysis of Structures - SS 15

E. Baeck
2

Basics in Python

2.1 Code Convention

In modern programming languages we can use nearly arbitrary names for variables, for functions, classes
and packages. Of course the names should be clear, i.e. the should not ambiguous. Sometimes however
it’s helpful to select names according to a name convention. If we use a name convention, we can put an
additional information into an item’s name, so that a developer can get this information without knowing
the details behind the code.

One of the first conventions was introduced by Charles Simonyi, a Hungarian software engineer, who
worked at Xerox PARC and later with Microsoft. This convention therefore is called Hungarian Notation.
The Hungarian Notation inspired from FORTRANs implicit name convention too, introduces some name
prefixes, which should show the developer some information about the variable usage.

With the emergence of the language Java a new code convention was introduced, which today is used in
many applications, so for example in the implementation of the Abaqus Python Interface. This we will
discuss in the second part (II). A short extract from this code convention, published by Sun Microsystems,
Inc. in 1997, we see in the appendix D.1.

From the Java Code Convention we use the following aspects.

1. Variable names will start with small letters.

2. Function names will start with small letters.

3. Class names will start with capital letters.

4. If names consists of several parts, we introduce every part except the first with a capital letter. This
is called camelCase, because of the shape of the camel’s back, the camel hump. Of course we do
not use white spaces inside the names, because this is not allowed.

15
Page 16 Analysis of Structures - SS 15

2.2 Reserved Words

We have seen in section 1.4, starting with a Python calculation within the Python shell is very easy. We
can use simple formulas with numbers or we can use symbolic names to make it more readable. In
Python like in other programming languages there are some reserved word, which are used to build up
the language. This words can not be used as variable names.

The reserved words of the Python language are the following.

and del from not while


as elif global or with
assert else if pass yield
break except import print
class exec in raise
continue finally is return
def for lambda try

If you want to use such a word it’s recommended to extent the name with an underscore, like vor example
break_ instead of break.

2.3 Packages and Modules

A package within Python is a container of software objects, global variables, functions and objects. In C
or Fortran, a package could be termed as library.

Packages should be imported into the Python session or into the Python source file, if external feature
should be used. A typical package import is the import of the mathematical package. This is necessary
if you want to call some basic mathematical functions like trigonometric functions or the square root. If
such a package is not imported, it’s objects, especially it’s functions, are unknown and can not be used.

Packages are like header includes within the C language. In C as well, external functions, whose headers
are not included, are unknown and can not be called.

2.3.1 Import of a whole Module or Package

A whole package is imported with the statement "import" module. The following example shows
the import of the mathematic package to apply the square root function. With the import statement the
module math will be linked. The square root function sqrt will be then available with the usual dot access
math.sqrt.

1 >>> import math


2 >>> math.sqrt(4)
3 2.0

E. Baeck
2.3. PACKAGES AND MODULES Page 17

2.3.2 Import all Names of a Module

If we only want to import all symbolic name of a module (package), we use the star as a wild card. The
following example shows the import of all names of the module math. If we do this, we can use all
functions of the module without prefixing it.
1 >>> from math import *
2 >>> sqrt(4)
3 2.0
4 >>> fabs(-2.)
5 2.0

2.3.3 Selective Import of Module Names

If we only want to import a symbolic name of a module (package), then we can import in a selective
way. The nex example shows the selective import of the function sqrt from the module math. If we do
this, then the function can be used without the prefixing module name.
1 >>> from math import sqrt
2 >>> sqrt(4)
3 2.0
4 >>>

2.3.4 Import with new Names

If some names of of module should be imported with new names, the statement as can be used within
the import statement. The following example shows the import of the trigonometric functions sin and
cos with the new names s and c and the constant pi with it’s original name, to calculate the Cartesian
ordinates of a 45 point with radius 10.
1 >>> from math import sin as s, cos as c, pi
2 >>> r = 10
3 >>> x = r*c(pi/4)
4 >>> y = r*s(pi/4)
5 >>> x
6 7.0710678118654755
7 >>> y
8 7.0710678118654746
9 >>>

You see, that we change the original name of the trigonometric functions with the as key word. Within
the formulas the functions can be used with it’s new names.

8.5.2018
Page 18 Analysis of Structures - SS 15

2.4 Operators

We have already seen, that Python also has it’s operators calculation the height of a vertical thrown
ball. Python uses the same precedence as we know form the mathematics. The power operation has the
strongest binding followed by the point operators (products and divisions) followed by the line operators
(plus and minus). Unary operators will always be applied first. To change the standard precedence of the
operators we use like in mathematics parenthesis to dictate the way a formula should be evaluated.

2.4.1 Unary Operators

Unary operators are working only on one value, therefor unary. In Python there are three unary operators
available.

Operator Comment Example


+ plus operator a = 2 >>> x = +a >>> +2
- minus operator a = 2 >>> x = -a >>> -2
˜ bitwise inversion a = 2 >>> x = ˜a >>> -3

The bitwise inversion shows the internal representation of negative numbers. A negative number is
represented by the so called b-complement of a number. This is the complement, i.e. the bitwise inverted
number plus 1. So we get

−a =∼ a + 1 or ∼ a = −(a + 1) (2.1)

2.4.2 Arithmetic Operators

Python offers the following arithmetic operators. You should be careful with the usage of data types
especially within divisions. If you use integers, the result generally will be truncated.1

Operator Comment Example


+ sum operator x = 2+3 >>> 5
- substraction operator x = 4-2 >>> 2
* product operator x = 2*4 >>> 8
/ division operator x = 9/2 >>> 4
x = 9./2. >>> 4.5
** power operator x = a**2
% modulo operator x = a%2
// integer division operator x = a//2

1
The exception of the power operator all the arithmetic operators are used with the same symbol like in C. In C there is no
power operator available.

E. Baeck
2.4. OPERATORS Page 19

2.4.3 Bit Operators

Like in C bit operators can be easily be used to manipulate a number’s bits. The following operators are
available2

Operator Comment Example


& bitwise AND x = 23 & 13 >>> 5
ˆ bitwise exclusive OR x = 23 ˆ 13 >>> 26
| bitwise OR x = 23 | 13 >>> 31
<< left shift of bits x = 4 << 2 >>> 16
>> right shift of bits x = 4 >> 1 >>> 2

The left shift of a numbers bit by 1 is equal to a multiplication by 2. The right shift by one is the same as
a division by 2. The bitwise AND and OR operator are usually used to set or to clear a number’s bits.

The following example shows how to apply the shift operator. We start with the bit 0, which has the
value 1. Within a for loop (see section 2.9) the bit is shiftet subsequently to the left. So we create the bits
in the range from n to m. After shifting the bit, it’s value is printed into the console window.

Listing 2.1: List the Bit’s Values

1 # print the value the bits from bit n to bit m


2 #
3 n = 1
4 m = 10
5 bit0 = 1
6 for i in range(n,m+1):
7 bit_i = bit0 << i
8 print "Bit %2d = %6d" % (i,bit_i)

2.4.4 Extended Assign Operators

An extended assign operator combines the effect of an operator with the assignment to the involved
variable. This is inherited from the language C. In the table below we start with a variable x = 2.

Operator Comment Example


+= add and assign x += 1 >>> 3
-= substract and assign x -= 1 >>> 1
*= multiply and assign x *= 2 >>> 4
/= divide and assign x /= 4 >>> 0.5
<<= left shift and assign x <<= 2 >>> 8
<<= right shift and assign x >>= 1 >>> 1
|= or and assign x |= 4 >>> 6
&= and and assign x &= 8 >>> 0

2
Python’s bit operators are exactly the some as the C bit operators.

8.5.2018
Page 20 Analysis of Structures - SS 15

2.4.5 Manipulating Bits and Hexadecimal Numbering System

If we want to manipulate a number’s bits it is obvious more clearly to use the hexadecimal representation
of a number as using the elsewhere usual decimal representation. Hexadecimal numbers starts with the
literal 0x3 and uses the digits 0-9 and A-F. F is with 15 the largest digit of the hexadecimal numbering
system. The hexadecimal numbering system has the advantage, that it packs 4 bits of a number into one
hexadecimal digit. So a byte can be represented by 2 hexadecimal digits. If we now be able to translate a
hexadecimal digit into a binary number, then we can see even the bits in the largest number without any
calculation.

In the following example we want to analyze the arbitrary number 27563. The bits are obviously very
hidden using the decimal representation. To get a hexadecimal representation we can simple print the
number using the X formating. We can see that we obviously use two bytes for this number, because wie
get 4 digits (6BAB). Furthermore we can see, that the leading bit is not set, because the largest digit is 6
and the highest bit in a digit has the value 8.
1 >>> a = 27563
2 >>> "%X" %a
3 ’6BAB’
4 >>>

The binary number representation is easily available from the hexadecimal representation, if we know
the binary representation of the hexadecimal digits4 .

616 = 610 = 4 + 2 = 01102


A16 = 1010 = 8 + 2+ = 10102
B16 = 1110 = 8 + 2 + 1 = 10112

So we get assembling the binary digits of 6BAB the following bit sequence.

2756310 = 6BAB16 = 0110|1011|1010|10112 (2.2)

If we now want to set the highest bit of the discussed number, we can use the bitwise OR operator | (see
section 2.4.4). A number with only the highest bit set we can obtain by shifting the first bit to the desired
position within the 2 bytes, i.e. we shift the bit 15 times. Now we can see that we get a hexadecimal
number with only the highest digit non vanishing. Within the digit of 8 the forth bit is set, which is the
highest of a have byte5 .
1 >>> b = 1
2 >>> b = b<<15
3 >>> b
4 32768
5 >>> "%X" % b
6 ’8000’

If we now want to set the highest bit of our original number 27563, we simple can overlay it with the last
number 8000.
3
A binary number starts with the literal 0b and uses the digits 0 and 1, like 0b1000 = 810 .
4
The index of the example’s numbers represent the base of the numbering system.
5
A half byte is also called nibble.

E. Baeck
2.4. OPERATORS Page 21

1 >>> a = 27563
2 >>> b = a | (1<<15)
3 >>> b
4 60331
5 >>> "%X" % b
6 ’EBAB’

After having set the highest bit, we see that the decimal number has changed totally. However the
hexadecimal number only changes in the first digit. Instead of 6 we have now E. And E is represented
binary with
E16 = 1410 = 8 + 4 + 2 = 11102
so we get
6033110 = EBAB16 = 1110|1011|1010|10112 (2.3)
Comparing the binary result with the binary result of equation 2.2 we see that obiously only the first bit
is set as wanted.

How we can now clear a bit of a number? Clearing a bit of a number uses two steps. First we have to
create the inverse of the filtering number, having set only the desired bit. And within a second step we
use the AND operator & to overlay bitwise the inverse of the filtering number and the number, whose bit
should be cleared. In our example we want to clear the highest bit of the first byte. The filtering number
we get shifting the 1st bit 7 times.
1 >>> a = 27563
2 >>> b = a & (˜(1<<7))
3 >>> b
4 27435
5 >>> "%X" % b
6 ’6B2B’

We also notice, that the decimal representation has changed widely after the clearing of the bit on the
contrary to the hexadecimal.
2743510 = EB2B16 = 1110|1011|0010|10112 (2.4)

2.4.6 Comparison Operators

Boolean operators are used to branch and to make decisions. The comparing operators are identical to
the C comparing operators.6

Operator Comment Example


< less than x = 23 < 13 >>> False
<= less equal x = 23 <= 23 >>> True
> greater x = 23 > 13 >>> True
>= left shift of bits x = 23 >= 23 >>> True
== equal x = 23 == 23 >>> True
!= non equal x = 23 != 23 >>> False
<> not equal x = 23 <> 13 >>> False
6
There are two identical non equal operators available. ! = is C like, and <> is Basic like, the later one is obsolete and
taken from Phyton 3.

8.5.2018
Page 22 Analysis of Structures - SS 15

The result of a boolean expression like above are the boolean values False or True. To combine
comparing expressions the following logical operators can be used.7

Operator Comment Example


and logical and x = 1 < 2 and 2 < 3 >>> True
or logical or x = 1 < 2 or 2 > 3 >>> True
not logical not x = not (1 < 2) >>> False

The following table shows the truth values of the && and the || operator.

Truth tabel of the && operator Truth tabel of the || operator


a b a && b a b a || b
true true true true true true
true false false true false true
false true false false true true
false false false false false false

2.4.7 Membership Operators

With the membership operators you can check whether a value or an object is part of sequence of objects.

Operator Comment Example


in is member x = 2 in (1,2,3) >>> True
not in is not a member x = 2 not in (1,2,3) >>> False

2.4.8 Identity Operators

With the identity operators you can check the identity of two objects.

Operator Comment Example


is is identical x = (1,2) >>> y = x >>> x is y >>> True
is not is not identical x = (1,2) >>> y = x >>> x is not y >>> False

7
To make expressions clear parenthesis should be used. A term within a parenthesis is evaluated first and it’s result then is
used in further evaluations outside the parenthesis. With parenthesis the order of the evaluation can be set.

E. Baeck
2.5. PRINT AND OUTPUT FORMATS Page 23

2.5 Print and Output Formats

If you want to print data into the console window, you have to think about formating. The formating
sequences are very similar to the formating sequences of the C printf function. The formating is a so
called escape sequence within a string, which is started with the % operator.

The most common formats are the following.

• formating an integer
An integer (independent of the data type) is formated by the escape %d for decimal representation
and %x or %X for hexadecimal representation.

• formating a float
A float is formated by the escapes %f, %e, %E, %g and %G

• formating a string
A string is formated by the escapes %s

A leading number n within a format %nT, with T the type of the format, sets up the width of the output.
The following example shows the formating of an integer in decimal and hexadecimal mode. At the
hexadecimal format a lower x sets lower digit letter, the capital X sets capital digit letters.
1 >>> "%d,%3d,%6d" % (2,2,2)
2 ’2, 2, 2’
3 >>> "%x,%3X,%6X" % (31,31,31)
4 ’1f, 1F, 1F’

Formating floats there are two different formats available, the fixed format and the exponential format,
which is also called scientific format. The f format sets a non exponential representation. The e or E
format sets a exponential format. e uses a small e letter, and E uses a capital E letter. The g or G format
sets an optimized representation, i.e. a fixed or an exponential format, depending on the outputs length.
The number after the dot sets the number of digits after the comma for f and e format, it sets the number
of significant digits for the g format.
1 >>> "%f,%e,%g" % (12.34,12.34,12.34)
2 ’12.340000,1.234000e+01,12.34’
3 >>> "%.2f,%.2e,%.2g" % (1234567.89,1234567.89,1234567.89)
4 ’1234567.89,1.23e+06,1.2e+06’

8.5.2018
Page 24 Analysis of Structures - SS 15

2.6 Basic Data Types

Recording to the available data types, Python is very different comparing it with common languages like
C, Fortran and Basic. Most of the languages offers the programmer data types, which are one by one
related to the underlaying hardware.

So for example Fortran and C offer 2 and 4 byte integers on 32 bit operating systems by default8 On a
64 bit operating platform a long integer of 8 bytes will be available. On the other hand there are 4 and 8
byte floats available.

Python however offers on 32 bit platforms a normal integer of 4 bytes, which is directly related to the
hardware, for example 11234, and furthermore a so called long integer, for example 1234L, which is
handled by the Python software. The long integer, which is marked by a succeeding L, is only restricted
by the computers memory, that means that a really incredible number of digits can be considered. Later
we will calculate the factorial of a incredible high number.

Furthermore Python as already mentioned offers only one float data type with 8 bytes. The standardized
4 byte float is not supported, for example 1.23 or 1.23e+2.

Python also supports a complex arithmetic with an complex data type, consisting of two floats for real
and imaginary part of the complex number. The complex unit in Python is called j. Therefor the complex
number 1 + 4i will be represented in Python with 1 + 4j.

The last data type used in Python is a string consisting of one or more characters.

The data type of a variable can be determined using the build in function type, as shown in the following
example. Within a first step different variables were created by a simple assignment. The content of the
variable determines the type of the variable, no explicit declaration is needed or available, like in C. After
having created the variables the type of the variables will be determined by subsequent type calls.

To check the data type within a program the following tests can be made.

1. if type(d).__name__ == ’int’
You can check the type with the types __name__ member.

2. if type(d) == int
... or you can check the type with the type class name (discussed later).

1 >>> a = 2
2 >>> b = 3L
3 >>> c = 4.5
4 >>> d = 6 + 7j
5 >>> e = "Hello World"
6 >>> type (a)
7 <type ’int’>
8 >>> type (b)
9 <type ’long’>
10 >>> type (c)
11 <type ’float’>
12 >>> type(d)
13 <type ’complex’>

8
That means without applying provider depended tricks.

E. Baeck
2.7. CODE BLOCKS Page 25

14 >>> type(e)
15 <type ’str’>

You see, ’int’ is integer, ’long’ is long integer, ’float’ is float, ’complex’ is complex and
’str’ is string data type.

Furthermore there are some sequences in Python available, which combines the mentioned data types in
a more or less sophisticated mode. More about that later.

2.7 Code Blocks

One very imported feature of Python is, that code blocks are bracketed by an unique indent. The most
programming languages uses there specific code parenthesis. There is one opening parenthesis which
starts the code block and there is one closing parenthesis, which closes the code block.

The following example shows a code block in C.


1 if (a > b)
2 {
3 c = a + b
4 d = a - b
5 ... Further Lines of C-Code ...
6 }

The following example shows a code block in Fortran77.


1 if (a .gt. b) then
2 c = a + b
3 d = a - b
4 ... Further Lines of Fortran-Code ...
5 endif

Compared with this in Python the code block is bracketed by indent as follows.
1 if a > b:
2 c = a + b
3 d = a - b
4 ... Further Lines of Python-Code ...
5 a = b

One statement which uses a code block, in this case an if statement, is closed by a colon. After the colon
an unique indent for the lines of the code block must be used. If not, it will be a syntax error. The code
block is closed, if the last line of the code block is the last line of the whole code, or is closed by a line
of code which is indented like the opening statement. In our example the assignment a=b has the same
indent as the if statement and so this line will be the first line of code outside our code block.

8.5.2018
Page 26 Analysis of Structures - SS 15

2.8 Globales

In Python a variable will be created, if an assignment is done. If so, it is impossible to access a variable,
which is introduced elsewhere, i.e. a global variable. If we now want to access such a variable, we have
to declare it inside our local function as a global variable. If we do this, the Python interpreter is looking
for a variable with such a name inside the name space of the calling function.

Example 2.2 shows how to access a global variable and which effect we have, if the value is changed
inside the called function.

Listing 2.2: Testing Global Variables

1 # usage of global
2

3 def doSomething(a):
4 global b
5

6 print "doSomething...: a = %d, b = %d" % (a,b)


7

8 a = 10 # local variable
9 b = 20 # global variable
10 c = 30 # local variable
11 print "doSomething...: a = %d, b = %d, c = %d" % (a,b,c)
12

13 a = 1
14 b = 2
15 c = 3
16 print "before calling: a = %d, b = %d, c = %d" % (a,b,c)
17 doSomething(a)
18 print "after calling.: a = %d, b = %d, c = %d" % (a,b,c)

Listing 2.3: Output from the Testing Example

1 before calling: a = 1, b = 2, c = 3
2 doSomething...: a = 1, b = 2
3 doSomething...: a = 10, b = 20, c = 30
4 after calling.: a = 1, b = 20, c = 3

In the output listing from our little testing example 2.2 we see, that the value of the global variable b
is overwritten by the function call, the value of the local variable a only is changed inside the function.
After the function call we see, that the variable a remains untouched by the function call.

E. Baeck
2.9. LOOP FOR REPETITIONS Page 27

2.9 Loop for Repetitions

Like all programming languages, which make sense, Python also has some implementations of repe-
titions, of loops. Like in C an explicit loop is available - the for loop - as well as an implicit loop is
available - the while loop.

The for loop is controlled by an iterated set. One very common variant is the for loop, which is controlled
by an iteration counter. The iteration counter will be configured by a range object. The range object has
3 parameters9 . The first parameter sets the start value of the iteration counter, the second parameter sets
up the iteration value, which will be the first value that is not performed. The third parameter sets up the
increment.

2.9.1 The Factorial

The following typical example for the usage of an iterative for loop implements the calculation of the
factorial.
n
Y
n! = i (2.5)
i=1

The implementation of the factorial is given below. Note the importance of the indent, see section 2.7.
1 n = 10 # factorial input
2 p = 1 # result variable must be initalized by 1
3 for i in range(2,n+1): # the counter runs from 2 up to n
4 p *= i # here we perform the product
5 print "%3d! = %10d" % (n,p) # write the result into the console
6

7 >>>... console window ...


8 10! = 3628800

The second loop type, the while loop is working implicit with a boolean expression, which controls the
break condition. If we want to implement the factorial using the while loop we get the following code.
1 n = 10 # factorial input
2 p = 1 # result variable must be initalized by 1
3 i = 2 # the counter runs from 2 up to n
4 while i <=n: # loop with break condition
5 p *= i # perform the product
6 i += 1 # explicit incrementation
7 print "%3d! = %10d" % (n,p)
8

9 >>>... console window ...


10 10! = 3628800

9
A parameter is a information unit, which is passed to the called object. If more then one parameter is passed, the parameters
are separated by commas.

8.5.2018
Page 28 Analysis of Structures - SS 15

The next example shows a nested loop. Very important is the correct code block indent.
1 for i in range(0,4): # outer loop
2 for j in range(0,2): # inner loop
3 print "i:%2d, j:%2d" % (i,j) # print counter variables
4

5 >>>... console window ...


6 i: 0, j: 0
7 i: 0, j: 1
8 i: 1, j: 0
9 i: 1, j: 1
10 i: 2, j: 0
11 i: 2, j: 1
12 i: 3, j: 0
13 i: 3, j: 1

For the detailed controlling of the loops cycles two statements are available.

• continue
If the continue statement is used a cycle is immediately stopped and the next cycle is started.

• break
If the break statement is used a cycle is immediately stopped and the loop is exited.

The next example shows an application of the continue statement. A loop is performed with the values
0 · · · 4. The cycle with the counter 2 is prematurely canceld.
1 >>> for i in range(0,5):
2 ... if i == 2: continue
3 ... print "i=%d" % i
4 ...
5 i=0
6 i=1
7 i=3
8 i=4

One very interesting feature of Python is the long integer arithmetic. So we can calculate incredible large
factorials. Figure 2.1 shows the code in the upper window. The console window shows the result. A
number with a lot of digits and every digit is exact.

The next example shows the calculation of the factorial using a float. The float factorial can only be
evaluated up to 170! = 7.25742e+306. In the case of 400! we will get an overflow, because the
exponent exceeds the available memory in 8 bytes (see figure 2.2).

E. Baeck
2.9. LOOP FOR REPETITIONS Page 29

Figure 2.1: Calculating the Factorial for a long integer

Figure 2.2: Calculating the Factorial for a float

8.5.2018
Page 30 Analysis of Structures - SS 15

2.9.2 Floating Point Precision

The Precision-Finder is a nice little program, which analysis the relative precision of a given float format.

2.9.2.1 Description of the Application

As we know, the computer cannot handle an infinite number Start


of floating-point digits. Therefore it is important to know who
many digits are available in a floating-point format (float).
Figure 2.3 shows a flow chart of an algorithm which continu- Initializing:
X1 = 1.; X2 = 1.; D = 2.;
ally reduces the value of a variable. After each reduction the
sum of the fixed and the reduced variable is calculated. If now
the contribution of the reduced is vanishing, we have reached Reductionstep:
X2 = X2/D;
the total limit. Beyond this limit the contributing information
is totally expunged. To get the relative precision, i.e. relating
to one, we have to take back the last reduction, if we have Accumulationstep:
reached the limit. S = X1 +X2;

2.9.2.2 Exercise yes


S > X1

Please implement the algorithm of the Precision-Finder for no


the Python float format within a little script like the famous Resultstep:
Hello World example (see section 1.3). Precission = X2 * D;

Stop

Figure 2.3: Flowchart for a Precision Finder

E. Baeck
2.10. FUNCTIONS Page 31

2.10 Functions

A function is a callable type. A function starts with the def command. The parameter list succeeds the
function name and consists of names separated by commas. The return of return values is optional. If
more then one return value should be given, the return values are separated by commas and the calling
code will get a tuple containing all the return values. A single return value is not returned in a tuple.

A nice example to study cases of a solution and their specific return values is discussed in section 2.11.
1 def <name> (Parameter list):
2 Code Block
3 return <Return Object list>

Listing 2.4 shows two functions with two parameters. The first function returns 3 values in a tuple, the
second function returns only one value. This value is returned without a tuple.

Listing 2.4: Functions with Parameters and Return Values

1 # function with 2 parameters and 3 returns


2 def myFunction1(a,b):
3 return a, b, a**b
4

5 # function with 2 parameters and 1 return


6 def myFunction2(a,b):
7 return a**b
8

9 # function with 3 parameters and 1 return in a tuple


10 def myFunction3(a,b):
11 return (a**b,)
12

13 ret = myFunction1 (2,3)


14 print "return of myFunction1... : ", ret
15 print "length of returned tuple : ", len(ret)
16

17 ret = myFunction2 (2,3)


18 print "return of myFunction2... : ", ret
19

20 ret = myFunction3 (2,3)


21 print "return of myFunction3... : ", ret
22 print "length of returned tuple : ", len(ret)

Runing the code of listing 2.4 will print the following output.
1 return of myFunction1... : (2, 3, 8)
2 length of returned tuple : 3
3 return of myFunction2... : 8
4 return of myFunction3... : (8,)
5 length of returned tuple : 1

8.5.2018
Page 32 Analysis of Structures - SS 15

2.11 Branches for Decisions

Decisions are made by the usage of the if statement. The if statement is defined as follows.
1 if [boolean expression 1]:
2 code block 1
3 elif [boolean expression 2]:
4 code block 2
5 elif [boolean expression 3]:
6 code block 3
7

8 ...
9 else:
10 code block else

2.12 Conditional Assignments

Like in languages like C/C++ in Python there is a similar conditional assignment available.
1 <variable> = <value_1> if <boolean expression> else <value_2>

In listing 2.12 we get an i value of 3, because b is true. Otherwise we would get a zero value.
1 b = true
2 i = 3 if b else 0 # in C: i = b ? 3:0;

2.12.1 How to Solve a Quadratic Equation

The calculation of roots of a quadratic equation is a nice and simple example to show the application of
the if statement. The quadratic equation is given by

a · x2 + b · x + c = 0 (2.6)

If we want to solve the quadratic equation, we have to analyze the available cases. A general solution
must handle the following cases.

• constant case
a=b=c=0

• linear case
a = 0, b 6= 0

• quadratic case
a 6= 0

• no solution case
a = b = 0 and c 6= 0

E. Baeck
2.12. CONDITIONAL ASSIGNMENTS Page 33

2.12.1.1 A Flow-Chart

The following flow chart shows all the case, which we have to handle. The algorithm is given for a real
arithmetic, i.e. no complex data types are used. The relevant source code will be developed within the
next section.
Start

yes yes yes infinit


a=0 b=0 c=0 Stop
solutions

no no no

d = b2 − 4 · a · c x= − cb Stop no solution Stop

yes √
−b±i −d
d<0 x1,2 = 2·a
Stop

no

−b± d Stop
x1,2 = 2·a

2.12.1.2 The Implementation

The implementation uses a real as well a complex arithmetic importing the module math and cmath. The
solver of the quadratic equation is implemented in a function called QuadSolve. The function analyzes
the different cases and returns in the constant case only a comment, in the linear case the solution value
and a comment. In the quadratic case 2 values and a comment were returned. All return values are
packed into a tuple. The case can be identified form the calling program using the function len, which
returns the number of items of a tuple. To branch in the real respectively the complex quadratic case, we
have to check the type of the returned result values using the Python function type. This we see in line
75. If the type is complex, we have to extract the real and the imaginary part of the number, to print it
using the print statement.

From line 44 on, we can see that using the complex square-root function cmath.sqrt automatically we
get a complex result. So it’s possible too, to return in any quadratic case a complex results. If so, we
don’t need to branch.

To avoid the testing for zero, which would produce numerical problems in principle, we set the relative
precision to 10−15 . An absolute value less then this relative precision is treated as zero value. Here we
apply the function fabs from the math package introducing the alias abs. Here we should know, that
Python provides a buildin function abs, which then will be overlayed by the fabs, so that the buildin is
visible no more.

8.5.2018
Page 34 Analysis of Structures - SS 15

Listing 2.5: Implementation of the Quadratic-Equation-Solver

1 ’’’
2 solution of a quadratic equation
3 - handling all special cases -
4 ’’’
5 # import the used functions
6 from math import fabs as abs, sqrt
7 import cmath
8

9 def quadSolve(a,b,c):
10

11 p = 1.e-15 # precision of float, is used to


12 # avoid to test for zero with ==
13

14 # case: a=0
15 if abs(a) < p:
16

17 # case: b=0
18 if abs(b) < p:
19

20 # case: c=0
21 if abs(c) < p:
22 return ("Infinit number of solutions.",)
23

24 # case: c!=0
25 else:
26 return ("No solution possible.",)
27

28 # case b != 0 (linear case)


29 else:
30 x = -c/b
31 return (x, "Linear case found.")
32

33 # case a != 0 (quadratic case)


34 else:
35 d = b**2 -4.*a*c
36

37 # real case
38 if d >= 0.:
39 s = sqrt(d)
40 x1 = 1./(2.*a)*(-b +s)
41 x2 = 1./(2.*a)*(-b -s)
42 return (x1,x2,"Real case of the quadratic problem.")
43

44 # complex case
45 else:
46 s = cmath.sqrt(d)
47 x1= 1/(2.*a)*(-b +s)
48 x2= 1/(2.*a)*(-b -s)
49 return (x1,x2,"Complex case of the quadratic problem.")
50

51 # -------- main program -------------------


52 # input section
53 a = 1.
54 b = 0.

E. Baeck
2.13. FUNCTION EXAMPLES Page 35

55 c = 4.
56

57 # call of QaudSolve function


58 result = quadSolve(a,b,c)
59

60 # check the result tuple, to select the found case


61 values = len(result)
62 print "%d values found in return" % values
63

64 # format the found result case


65 # no or infinit solution(s)
66 if values == 1:
67 print result[0]
68

69 # linear case
70 elif values == 2:
71 print "x = %f, info: %s" % result # (result[0],result[1])
72

73 # quadratic case
74 elif values == 3:
75 if type(result[0]) == complex:
76 print "x1 = %f+(%fi), x2= %f+(%fi), info: %s" \
77 % (result[0].real,result[0].imag,
78 result[1].real,result[1].imag,
79 result[2])
80 else:
81 print "x1 = %f, x2 = %f, info: %s" % result

2.13 Function Examples

In this section we will discuss a new abs function and the Newton algorithm using a function as parameter.

2.13.1 An Abs-Function with Type-Checking

The following code shows a special version of the abs function. The data type is checked first. Only int,
long or float type are senseful supported. We check the type with the type function. The type function
returns a type object. Within the function we check the object member __name__. If the type is not
supported, a error string is returned. If the type is supported, the return value is return. The calling
program checks the return values type using the object name (int, long and float).

Listing 2.6: Abs Function with Type Checking

1 # declaring our version of an abs function


2 def myAbs(x):
3

4 # process only sensful data types


5 # here we use the type class member __name__
6 # to check the data type
7 t = type(x).__name__
8 if t != ’int’ and t != ’long’ and t != ’float’:
9 return "Error: Type ’%s’ is not allowed." %t
10

8.5.2018
Page 36 Analysis of Structures - SS 15

11 # if data type ok change sign if necessary


12 if x < 0.: return -x
13 return x
14

15 # input section
16 y = -4 # test 1
17 # y = "hello" # test 2
18

19 # function call
20 z = myAbs(y)
21

22 # get return type


23 t = type(z)
24 if t == str: # second version to check the type
25 print z # print error message
26 else:
27 print "Absolute Value of %f = %f" % (y,z) # print result

2.13.2 The Newton-Algorithm

The following example shows, how to pass a function as


a functions parameter. Within the Newton’s algorithm
a root of an equation should be calculated. So we have
to specify the function of interest. This function can be
considered as an input parameter. This function name
is passed to the derivative calculator and to the newton
main routine. Further we see, that it’s recommended to
use standard parameter, to configure the algorithm. We
introduce the precision parameter e, which sets up the
threshold for a zero compare. Further we need the step
width to calculate the derivative of the function of our
Figure 2.4: Scheme of the Newton Algorithm
interest.

The derivative - it’s called fs in the code - is calculated numerical as follows.


 
0 df h h
f (x) = ≈ f (x + ) − f (x − ) /h
dx 2 2
(2.7)

The Newton scheme can be described as follows.


f (x)
xi+1 = xi − (2.8)
f 0 (x)

E. Baeck
2.13. FUNCTION EXAMPLES Page 37

There are three possible situations to handle within the iteration loop.

• The function value is vanishing with respect to our selected precision. The iteration loop will be
broken and the found result is passed back to the caller.

• The slope of the function is vanishing. This situation can not be handled by the simple iteration
scheme. The iteration will be broken with an error message.

• During the iteration each cycle is counted. So the iteration loop will be broken, if the maximum
available iterations are reached. The actual values and an error message is passed bake to the caller.

The following flow chart is given for a simple implementation of Newton’s algorithm.

Start

Initializing:
x = x0 ; i = 0;

yes
i ≥ imax NO ROOT! Stop

no

F x = f (x)

yes
|F x| ≤  ROOT: x Stop

no
F s = f 0 (x)

yes
|F s| ≤  NO SLOPE! Stop

no
Fx
x = x− Fs

i = i+1

Figure 2.5: Flow Chart for a Simple Newton Implementation

8.5.2018
Page 38 Analysis of Structures - SS 15

The code consists of the following functions.

• myF, the function of our interest.

• fs, the function which calculates the slope of a given function numerically.

• newton, implements the newton scheme.

Listing 2.7: Implementation of Newton’s-Alogrithm

1 from math import fabs as abs # import the fabs as abs


2

3 # implementation of the function of interest


4 def myF(x):
5 return x**2 +1.
6

7 # calculating the derivative


8 def fs(f,x,h=1.e-6):
9 h = float(h)
10 x = float(x)
11 return (f(x+0.5*h) - f(x-0.5*h))/h
12

13 # implementation of a newton algorithm


14 def newton(f,x0,e=1.e-10,h=1.e-6,imax=100):
15

16 error = None # initialize the error code with None


17

18 h = float(h) # we need some floats


19 e = float(e)
20 x1= float(x0) # x to interate
21

22 i = 1 # iteration counter
23 while True:
24

25 f0 = f(x1) # function’s value


26 if abs(f0) < e:
27 break
28

29 # calculating the derivative


30 f1 = fs(f,x1,h)
31 if abs(f1) < e:
32 error = "*** Error: vanishing derivate!"
33 break
34

35 # available iterations exceeded


36 if i >= imax:
37 error = "*** Error: no root found!"
38 break
39

40 # calculating the values for next iteration


41 x1 -= f0/f1
42

43 # increment the iteration counter


44 i+=1
45

46 # return the actual position, the function value

E. Baeck
2.14. DATA SEQUENCES Page 39

47 # and the functions slope, the number of performed


48 # iterations and the error code.
49 return (x1,f0,f1,i,error)
50

51 # the function newton is called with standard parameters


52 # we pass the function of interest and a supposed start
53 # position
54 res = newton(myF,4.)
55

56 # the returned tuple is printed into the console window


57 print res

2.14 Data Sequences

In Python there are some sequential data types available.

• Strings, a list of characters.

• Tuples are fixed sequences, which are only extensible. The advantage of tuples is the performance.

• Lists are changeable sequences but with lower performance.

2.14.1 Working with Tuples

The following example shows the creation of a tuple. An empty tuple is declared. We extend the tuple
with a one element tuple - note the comma. The second extension extends the tuple with a two element
tuple.
1 >>> t = () # initialize the tuple
2 >>> t
3 ()
4 >>> t += (1,) # append the tuple with a number
5 >>> t
6 (1,)
7 >>> t += (2,3) # append at tuple with a second tuple
8 >>> t
9 (1, 2, 3)
10 >>> t[0] # calling the tuple’s first element
11 1
12 >>> t[2] # calling the tuple’s third element
13 3
14 >>> t[3] # an error occur, if the index goes out of range
15 Traceback (most recent call last):
16 File "<interactive input>", line 1, in <module>
17 IndexError: tuple index out of range
18 >>> len(t) # the number of elements is given by the len function
19 3

8.5.2018
Page 40 Analysis of Structures - SS 15

Note, that tuples are input data for complex string formatings.

1 >>> "x1 = %8.2f, x2 = %8.3f" % (12.3456,12.3456)


2 ’x1 = 12.35, x2 = 12.346’

With the function tuple() a tuple can be created from an iterable object like string or list.

1 >>> T =tuple([1.,2.])
2 >>> T
3 (1.0, 2.0)
4 >>> L = list(T)
5 >>> L
6 [1.0, 2.0]
7 >>> T = tuple("Hello World")
8 >>> T
9 (’H’, ’e’, ’l’, ’l’, ’o’, ’ ’, ’W’, ’o’, ’r’, ’l’, ’d’)

Note, that the data of a list can be converted into a tuple using the function tuple() and reverse into a
list using the function list().

2.14.2 Working with Lists

Lists are more flexible as tuples. Creating and extending lists can be coded like in the case of tuples.
The only difference is, that lists uses in their declaration the [..] parenthesis. So using lists the code
example of the section 2.14.1 can be coded like follows.

1 >>> L = {] # initialize the list


2 >>> L
3 []
4 >>> L += [1,] # append the list with a number
5 >>> L
6 [1,]
7 >>> L += [2,3] # append at list with a second list
8 >>> L
9 [1, 2, 3]
10 >>> L[0] # calling the lists first element
11 1
12 >>> L[2] # calling the list’s third element
13 3
14 >>> len(L) # the number of elements is given by the len function
15 3

You can read somewhere, that tuples are much more faster than lists. This is surely not valid for every
problem. So it’s recommended to check the performance explicitly before you decide to use tuples or
lists.
The list object offers a wide set of methods. Some of them are discussed in the following table.

E. Baeck
2.14. DATA SEQUENCES Page 41

Methode Comment Example


append(i) Append an item to the list. Same as += operator. L.append(3)
count(x) Counts the value x in the list. L.count(1.2)
extend(s) Append a list to the list. Same as += operator. L.extend(t)
index(x) Evaluates the lowest index of the value x in the list. L.index(1.2)
insert(i,x) Inserts the object x before the item i. L.insert(2,1.2)
pop() Returns the last item and deletes it from the list. L.pop()
remove(x) Removes the first item with the value x. L.remove(1.2)
reverse() Invert the order of the items of a list. L.reverse()
sort() Sort the items of list in ascending order. L.sort(t)

A very important data object or container class which is used espe-


cially from the compiler to implement function calls is called stack.
A very common error situation is the so-called stack-overflow error.
This error will occur especially, if functions are called recursively. In
this case the return addresses are pushed to the stack to remember the
way back. If an address should be read from the stack, the address is
poped form the stack, which means, that the last value is read and this
Figure 2.6: Stack Operations
last value is removed from the stack.10 A stack is also called LIFO,
i.e. Last In First Out.

Figure 2.7 shows the history of a stack in use.


Onto the empty stack the H is pushed. The the
e, the l and the o are pushed. After that the o is
poped, that means the element is returned to the
caller and removed from the stack. With two fur-
ther pops the elements l and e are removed from
the stack. A further push stores the w on the stack.
After two pops the w and the e are removed. The Figure 2.7: Stack Example
H remains on the stack

Now, how can we implement a stack with basic Python? We simply need a list instance with the two
functions append(), which implements the Push and pop() which implements the Pop of a stack.

10
If we save data on a stack, it’s called push data onto the stack. If we take data from the stack, it’s called pop data from the
stack.

8.5.2018
Page 42 Analysis of Structures - SS 15

2.14.3 Working with Dictionaries

A dictionary is a powerful and very general container, it’s also called map, because a key value is mapped
onto the pointer of the stored item. In Python an instance pointers is stored in a dictionary using an
arbitrary key strings. So a dictionary is like a list container with a more general access. Because the
dictionary commonly hashes the key information onto some smaller index lists, the dictionary commonly
has a better performance as a linked list container. The dictionary therefore is used in the abaqus class
library (we will discuss it later) to store named instances.

A dictionary can be created like a list using curled parenthesis. Each key-value pair is separated by a
comma. The key is separated from the value by a colon.
1 >>> myDict = {’first item’:1, ’second item’:2}
2 >>> print myDict[’second item’]
3 2
4 >>> beatles = {}
5 >>> beatles[’drums’] = ’Ringo’
6 >>> beatles[’bass’] = ’Paul’
7 >>> beatles[’vocal’] = ’John, Paul, George, Ringo’
8 >>> beatles[’guitar’] = ’George, John’
9 >>> print beatles
10 {’guitar’: ’George, John’, ’vocal’: ’John, Paul, George, Ringo’, ’bass’: ’Paul’,
11 ’drums’: ’Ringo’}

2.15 Error Handling with Exceptions

There are (at least) two distinguishable kinds of errors: syntax errors and exceptions.11

2.15.1 Syntax Errors

Syntax errors, also known as parsing errors, are perhaps the most common kind of complaint you get
while you are still learning Python.
1 >>> while True print ’Hello world’
2 File "<stdin>", line 1, in ?
3 while True print ’Hello world’
4 ˆ
5 SyntaxError: invalid syntax

The parser repeats the offending line and displays a little arrow pointing at the earliest point in the line
where the error was detected. The error is caused by (or at least detected at) the token preceding the
arrow: in the example, the error is detected at the keyword print, since a colon (’:’) is missing before it.
File name and line number are printed so you know where to look in case the input came from a script.

11
Parts of this section are taken from the Python 2.7 manual.

E. Baeck
2.15. ERROR HANDLING WITH EXCEPTIONS Page 43

2.15.2 Exceptions

Even if a statement or expression is syntactically correct, it may cause an error when an attempt is made
to execute it. Errors detected during execution are called exceptions and are not unconditionally fatal. We
will see how to handle them in the next section. Most exceptions are not handled by programs, however,
and result in error messages as shown below.
1 >>> 10 * (1/0)
2 Traceback (most recent call last):
3 File "<stdin>", line 1, in ?
4 ZeroDivisionError: integer division or modulo by zero
5 >>> 4 + spam*3
6 Traceback (most recent call last):
7 File "<stdin>", line 1, in ?
8 NameError: name ’spam’ is not defined
9 >>> ’2’ + 2
10 Traceback (most recent call last):
11 File "<stdin>", line 1, in ?
12 TypeError: cannot concatenate ’str’ and ’int’ objects

The last line of the error message indicates what happened. Exceptions come in different types, and
the type is printed as part of the message: the types in the example are ZeroDivisionError,
NameError and TypeError. The string printed as the exception type is the name of the built-in
exception that occurred. This is true for all built-in exceptions, but need not be true for user-defined
exceptions (although it is a useful convention). Standard exception names are built-in identifiers (not
reserved keywords).

The rest of the line provides detail based on the type of exception and what caused it.

The preceding part of the error message shows the context where the exception happened, in the form of
a stack traceback. In general it contains a stack traceback listing source lines; however, it will not display
lines read from standard input.

2.15.3 Handling Exceptions

It is possible to write programs that handle selected exceptions. Look at the following example, which
asks the user for input until a valid integer has been entered, but allows the user to interrupt the program
(using Control-C or whatever the operating system supports); note that a user-generated interruption is
signalled by raising the KeyboardInterrupt exception.
1 >>> while True:
2 ... try:
3 ... x = int(raw_input("Please enter a number: "))
4 ... break
5 ... except ValueError:
6 ... print "Oops! That was no valid number. Try again..."
7 ...

The try statement works as follows.

• First, the try clause (the statement(s) between the try and except keywords) is executed.

• If no exception occurs, the except clause is skipped and execution of the try is finished.

8.5.2018
Page 44 Analysis of Structures - SS 15

• If an exception occurs during execution of the try clause, the rest of the clause is skipped. Then
if its type matches the exception named after the except keyword, the except clause is executed,
and then execution continues after the try.

• If an exception occurs which does not match the exception named in the except clause, it is passed
on to outer try; if no handler is found, it is an unhandled exception and execution stops with a
message as shown above.

A try may have more than one except clause, to specify handlers for different exceptions. At most
one handler will be executed. Handlers only handle exceptions that occur in the corresponding try
clause, not in other handlers of the same try. An except clause may name multiple exceptions as a
parenthesized tuple.
1 ... except (RuntimeError, TypeError, NameError):
2 ... pass

In the next example we open a file with the name ’input.dat’. We read one line and strip the leading and
trailing blanks. The result will then be converted to an integer. We know that this is not possible in every
case, so we want to handle possible errors by our error handler.
1 try:
2 f = open(’input.dat’) # let’s open then input file,
3 s = f.readline() # read the first line and
4 i = int(s.strip()) # strip the white spaces
5 except IOError as e: # catch the io-errors
6 print "I/O error(%d): %s" % (e.errno, e.strerror)
7 except ValueError: # catch conversion errors
8 print "Could not convert data to an integer."
9 except: # catch the rest
10 print "Unknown error!"

2.15.4 Raise Exceptions

If we want to avoid runtime errors, we have to check our data base. In an classical approach, we have to
check the data, and break each activity jumping back to the origin of our call. Sometimes especial if the
calling hierarchy is extensive, it becomes an evil and tedious work to do this. On the other hand in most
modern languages we can use exception handlers to do this work for us. The only thing we have to do
is, to raise our own exception and check for it within an except clause.

The first listing 2.8 we call our square root function with a negative value.

Listing 2.8: Our Unsave mySqrt-Function

1 import math
2

3 def mySqrt(x):
4 return math.sqrt(x)
5

6 print mySqrt(-2)

The program crashes with the following output.


1 Traceback (most recent call last):

E. Baeck
2.16. RANDOM NUMBERS Page 45

2 File "C:\Python27\Lib\site-packages\Pythonwin\pywin\framework\scriptutils.py",
3 line 326, in RunScript
4 exec codeObject in __main__.__dict__
5 File "C:\UniDue\CM\Cm-AoS\AOS-BookOfExamples\Py\Code\ExceptionEx01.py", line 7,
6 in <module>
7 print Sqrt(-2)
8 File "C:\UniDue\CM\Cm-AoS\AOS-BookOfExamples\Py\Code\ExceptionEx01.py", line 4,
9 in mySqrt
10 return math.sqrt(x)
11 ValueError: math domain error

We see that obviously the function sqrt is not able to handle negative numbers.

In the next example we check the root’s value and raise an exception to break the function. This exception
itself is caught by the main program with an try clause.

Listing 2.9: mySqrt-Function with Checking

1 import math
2

3 def mySqrt(x):
4 if x < 0.:
5 raise Exception("error: negative input value %e!" % x)
6 return math.sqrt(x)
7

8 try:
9 print mySqrt(-2)
10 except Exception as e:
11 print e

In listing 2.9 we see, that if negative values are passed, the function will raise an exception. Using the
Exception class we send a string information, which can be caught within the except clause. The
output of this version is given below.
1 error: negative input value -2.000000e+00!

We see, that the concept of an exception handling is a powerful feature to implement error checking.

2.16 Random Numbers

Because a computer is system, which works systematically reproducible, a computer will not be able to
create real random numbers. If we start a program twice with exact the same input values, the result also
will be the same. But with a little trick, we can produce so called pseudo random numbers. If we use
the time as input for the initialization of our random number generator, we will be sure, that it will be
extremely improbable, to get twice the same random number set.

So every programing language has it’s own random number generator. Python offers us a build-in pack-
age, which is called random. Like in C the random number generator is to initialize with a function
seed(). This function uses the computer time information to make varying starting conditions.

The following example will discuss two features of the Python library.

• How can we use the random package to create random numbers or to create a random order of
lists, i.e. shuffle the list’s data.

8.5.2018
Page 46 Analysis of Structures - SS 15

• How can we create simple 2d diagram plots using the matplotlib package.

The example code consists of three sections.

• At the beginning the lists xPos and yPos are filled with random numbers. This random x and y
values are interpreted as point coordinates. Two subsequent points are joint by a line.

• Within a second step the list’s element are sorted. The result is plotted again. The result is an
increasing function.

• Within the third step the sorted lists are shuffled by the random package. The random order of the
random numbers is plotted again.

Figure 2.8 shows the walk for random points (blue line), for sorted points (red line) and for shuffled
points (green line). The left figure shows the content of the created png file, the right figure shows the
plot within the viewers window.

Figure 2.8: Random, Sorted and Shuffled Walk

Listing 2.10: Implementation a Kind of Random Walk visualized with two Lists of Random Numbers

1 import random # import the random package


2 import pylab # part of matplotlib
3

4 # create random ’count’ numbers in the range [lower:upper]


5 # a list is returned to the caller
6 def getRandomNumbers(lower,upper,count):
7 random.seed() # initialization of random number generator
8

9 numbers = []
10 for i in range(count):
11 r = lower + (upper-lower)*random.random()
12 numbers.append(r)
13 return numbers
14

15 # main program ------------------------------


16 L = -10. # lower bound

E. Baeck
2.17. DATE, TIME AND TIMESPAN Page 47

17 U = +10. # upper bound


18 xN = 100 # number of randoms
19

20 # random positions
21 xPos = getRandomNumbers(L,U,xN) # ...in x-direction
22 yPos = getRandomNumbers(L,U,xN) # ...in y-direction
23

24 # creating plot of original random values xPos/yPos


25 pylab.plot(xPos,yPos,"b")
26

27 # sort the random values


28 xPos.sort()
29 yPos.sort()
30

31 # creating plot of sorted values xPos/yPos


32 pylab.plot(xPos,yPos,"r")
33

34 # create a random order


35 random.shuffle(xPos)
36 random.shuffle(yPos)
37

38 # creating plot of the shuffeled values xPos/yPos


39 pylab.plot(xPos,yPos,"g")
40

41 # save the plot in a figure using an png-format


42 pylab.savefig("RandomWalk.png")
43

44 # plot a figure in the matplotlib viewer


45 pylab.show()
46

47 # at the end we should close the plot,


48 # to avoid memory effects
49 pylab.close()

2.17 Date, Time and Timespan

Date and time functions in common are very important and therefor Python supports this with a stan-
dard package datetime. Within this package you will find some very simple and powerful objects and
functions.

The package is loaded with the following statement. We load from datetime the subpackage datetime
and set the alias name time. The second line shows, how to get the actual time. The datetime object
contents from the left to the right the year, the month, the day, the hour, the minutes, the seconds and
the microseconds. Because the computer does not support microseconds but milliseconds the measured
milliseconds are multiplied with the factor 1000.
1 >>> from datetime import datetime as time
2 >>> time.now()
3 datetime.datetime(2010, 11, 4, 19, 25, 33, 15000)

To implement some performance checking code it is very useful to have a timespan, which is the dif-
ference of two datetime objects. The timespan object is called timedelta and is as well an object of the
datetime package.

8.5.2018
Page 48 Analysis of Structures - SS 15

If we now want to check the performance of a code snippet, we will implement the following code.
First we have to import the datetime package. Then we get the actual time and assign this object to the
variable t1. Then the code to check follows. Within a last step we again create a datetime object calling
the time.now() function and assigning the object to the variable t2. If we subtract t1 from t2 we
will get a timedelta object. The timedelta objects contents the number of days, the number of seconds
and the number of microseconds of the time difference.
1 from datetime import datetime as time
2 t1 = time.now()
3 ... our code snippet ...
4 t2 = time.now()
5 t3 = t2 -t1
6 print t3
7 >>> datetime.timedelta(0, 12, 906000)

If we want to have the time difference in seconds, we have to write a little function, which adds all this
time parts in the unit second. If we suppose, that T is a valid timedelta object, we extract the seconds with
the seconds attribute and assign it to our seconds variable. The next part handles the microseconds.
We divide them by 106 and add the part to the seconds variable. The last part calculates the seconds of
the given hours and add this value to our second variable. The value is returned to the caller.
1 def getTimeSpanInSeconds(T):
2 secs = float(T.seconds)
3 secs += float(T.microseconds)/1.e6
4 secs += float(t.days)*24.*60.*60.
5 return secs

One very important application of the timedelta object is the measurement of a program’s performance.
The next example shows how to investigate the performance of the creation of a tuple and the creation of
a list. Here we apply the above discussed function getTimeSpanInSeconds.

Listing 2.11: Implementation of a Performance-Checker

1 # we need the datetime package


2 from datetime import datetime as time
3

4 # calculating the timespan in floats


5 def getTimeSpanInSeconds(T):
6 t = float(T.seconds)
7 t+= float(T.microseconds)/1.e6
8 t+= float(T.days)*24.*60.*60
9 return t
10

11

12 nX = 100000 # number of entities to create


13 T = () # empty tuple
14 L = [] # empty list
15

16 # create a tuple with nX items


17 t1 = time.now()
18 for i in range(nX):
19 T += (i,)
20 t2 = time.now()
21

22 sT = getTimeSpanInSeconds(t2-t1) # and calculate the timespan

E. Baeck
2.18. WORKING WITH FILES Page 49

23 print "Creation of a tuple with %d items: %.3fs" % (nX,sT)


24

25 # create a list with nX items


26 t1 = time.now()
27 for i in range(nX):
28 L += [i,]
29 t2 = time.now()
30 sL = getTimeSpanInSeconds(t2-t1) # and calculate the timespan
31 print "creation of a list with %d items: %.3fs" % (nX,sL)
32

33 # convert the list into a tuple


34 t1 = time.now()
35 TL = tuple(L)
36 t2 = time.now()
37 sTL= getTimeSpanInSeconds(t2-t1) # and calculate the timespan
38 print "Create tuple from list: %.3fs" % sTL

The console output on a one year old double processor notebook is given below. You see that it is very
wasteful to create a tuple with a lot of items concatenating them with a += operator. On the other hand a
list with the some number of items is created in no time. And the conversion of a list into a tuple costs
nothing. So we can resume the the creation of a very large tuple should be done by creating a list and
converting it into a tuple.
1 c:\CM\Cm-AoS\WS1011\Python>Timecheck1.py
2 Creation of a tuple with 100000 items: 33.297s
3 Creation of a list with 100000 items: 0.063s
4 Create tuple from list: 0.000s

2.18 Working with Files

A file is a sequence of bytes written to an external media like a hard disk, a CD or an USB stick. A file’s
bytes are indexed with an integer. So the the fist byte of a file has the index 0 and the second byte the
index 1 and so on. A text file is structured with a line break character \n. If a text line should be read,
the io12 system reads all the bytes up to the next line break.

Python as a lot of functions which are able to handle every situation concerning files. So files can be
created. We can read data from a file or write data into a file. We can close a file. We can delete a file or
change it’s permissions.

2.18.1 Open a File

Within Python a file is an object an has a lot of attributes and methods (see also the next section). The
access to a file is initialized with the file constructor. The file constructor needs the name of the file and
the type of access. The file access type is like C’s access type of the function fopen13 . The type ’r’ is
used to read from a file, the type ’w’ is used to create a new file for writing. An old still existing file
will be deleted. The type ’a’ is used to write appending to an existing or a new file. If we want to read
from and write into a file the type ’w+’ can be used.
12
io means input output.
13
The function fopen is C’s classical function to open a file. The return will be a pointer to a FILE structure.

8.5.2018
Page 50 Analysis of Structures - SS 15

1 f = file(<filename>,<access-type>)
2 ...
3 ... example ...
4 ...
5 f = file("myfile.txt", "w")

2.18.2 Write Data into a File

The file method write writes a stream of bytes into a file. In contrast to the print function the write method
adds no carriage return to the file. If a line of text should be written, the text should be closed with an \n
character.
1 #> f.write(<byte-stream>)
2 #> ...
3 #> ... example ...
4 #> ...
5 f.write("This is my first line\n")

2.18.3 Close a File

After the usage of a file, the file should be closed.


1 #> f.close()
2 #> ...
3 #> ... example ...
4 #> ...
5 f.open("log.txt","a")
6 f.write("Write a little log line\n")
7 f.close()

2.18.4 Read Data from a Text File

A frequently problem is parsing an input file for some control data. This we can do with a statement
which reads the entire file into a list container using the method readlines. If we have read this lines then
we can iterate this container using the for statement. Doing this we will get line by line.

A line is a string which is terminated by a carriage return character. This string we can split up into
pieces using white spaces (blanks and tabs) as separators.

Listing 2.12: Read Data from a Text File

1 # import the fileinput package


2 import fileinput
3

4 h = -1. # initialize H value


5 w = -1. # initialize W value
6

7 file = open("data.in") # open the file


8 lines = file.readlines() # read entire content
9 file.close() # close the file
10 print lines # check the container
11

E. Baeck
2.18. WORKING WITH FILES Page 51

12 for line in lines: # iterate all lines


13

14 words = line.split() # split up into pieces


15

16 if len(words) < 1: continue # ignore blank lines


17 if words[0] == "#": continue # ignore comment lines
18

19 if words[0] == "H": # evaluate H key


20 h = float(words[1])
21

22 elif words[0] == "W": # evaluate H key


23 w = float(words[1])
24

25 print "h = %8.2f" % h # print H value


26 print "w = %8.2f" % w # print W value

In our example we want to read and analyze the input file data.in (see listing 2.13).

Listing 2.13: Key Value Input Control File

1 # this is a comment
2 # format is key - value like
3 H 100.
4 W 10.

If we run the script 2.12 we will get the console output 2.14. In line 1 we can see, that readlines will
create a list container (see square brackets).

Listing 2.14: Consol Output

1 [’# this is a comment\n’, ’# format is key - value like\n’, ’H 100.\n’, ’W


10.\n’]
2 h = 100.00
3 w = 10.00

8.5.2018
Page 52 Analysis of Structures - SS 15

2.18.5 A Logger-Function

In many cases it is very useful to have logging, to know, what is going on in an application. A logging
function has to flush the data after every write event to the disk to avoid the loss of data. If a write event
is executed first the data is written into a buffer memory. So if the program is crashing before the data
are written physically to the disk, the data are lost and the effect of such a log is rather suboptimal. One
very secure kind of logging is, to open a file for writing in append mode, write the desired data to the file
and close the file after having written the data. This is secure but the performance is low.

In the next example an implementation of a logging function is given. Later we will implement this
function as part of a logger class.

Listing 2.15: Implementation of a Logger-Function

1 # the filename is passed as a first argument,


2 # the string to print ist passed as a second
3 def appendLog(filename,text):
4

5 t = time.now() # get actual time


6 tstamp = "%2.2d.%2.2d.%2.2d|" % (t.hour,t.minute,t.second)
7 textout = tstamp + text # copy the stamp in front of the comment
8

9 f = file(filename,"a") # open the log file for appending "a"


10 f.write(textout + "\n") # write the text into the file with linebreak
11 f.close() # close the log, to save the data on disc
12

13 print textout # write the log to the screen

E. Baeck
2.19. OOP WITH CLASSES Page 53

2.19 OOP with Classes

Python is an object orientated programing language14 . Everything within Python is implemented as an


object, even a simple integer number. So what is the concept of a class? A class or an object combines
data, called attributes, with functions, called methods. This can be described by so called UML15

An instance of a class, that is the realization of the class in memory, is created simply by assigning the
class’s name followed by the constructors parameter list to a symbolic name, which than is the pointer or
the reference to this instance. Within the class the self pointer to the actual instance is called self. To
access member attributes or methods of a class the dot notation is used, i.e. <instance>.<member>.
We can remove an instance of a class by calling the del operator (del example). The references
to an instance are handled by the python runtime system. If an instance has lost all it’s references, the
instance is removed from the memory.16

2.19.1 Some UML Diagrams

UML structure diagrams of the emphasize the things that must be present in the system being modeled.
Since structure diagrams represent the structure they are used extensively in documenting the architec-
ture of software systems. In our description of the examples we want to implement we use the Class
Diagram which describes the structure of a system by showing the system’s classes, their attributes, and
the relationships among the classes.

A UML class diagram (see figure 2.9) consists of a Class Name


rectangular box, which is divided into three sections. Additional informa-
The fist section contents the class’s name. This name Attributes tion within a simple
Note diagram
is written centered in bold letters. The second section
Methods
contents the attribute’s names of the class and the third
section contents the method’s names. Figure 2.9: A UML Class and Note Diagram

A UML note diagram (see figure 2.9) consists of a stylized note sheet which is filled with some informa-
tion.

MyClass
this is my 1st class
Attribute1 A UML note diagram (see figure 2.10) will be assigned
Attribute2 to an other component of the diagram scene with a sim-
ple line.
Method1
Method2

Figure 2.10: A UML Note Diagram Assignment

14
Object orientated Programming is often used with the abbreviation OOP.
15
The Unified Modeling Language includes a set of graphic notation techniques to create visual models of software-intensive
systems. The Unified Modeling Language is an international standard see [4], UML 2.3 was formally released in May 2010.
16
This is also called Garbage Collector. In contrast to this in poor C or C++ an once allocated object has to be removed
explicitly from the memory to avoid so called memory leaks, this are blocked parts of the applications memory, which remain
unaccessible until the application is closed.

8.5.2018
Page 54 Analysis of Structures - SS 15

Figure 2.11 shows how to draw diagrams for inheriting Base Class Derived Class
classes. An arrow with a white filled arrowhead points
from the inheriting class, the special class, to the inher- − attributeB1 + attributeS1
ited class, the base class. The attributes and the methods − attributeB2 − attributeS2
of the Base class are now available in the name space of
− methodB1 + methodS1
the inheriting class, i.e. the derived class now has the at-
+ methodB2 + methodS2
tributes attributB1, attributB2, attributS1 and
attributS2. Figure 2.11: A UML Inheritance Diagram

The prefixes + and − describe the access permissions. + items are accessible from outside. In C++
they get the public attribute. − items are not accessible from outside, only methods of their class are
allowed to access. In C++ they get the private attribute.

There are to different class items, an item which is related only to a class Base Class
and an item which is related to an instance. An instance related item needs
an instance. So if an instance is created the item is available with this − attributeB1
instance pointer. Without an instance the item is not available. So an − attributeB2
instance related item can have an arbitrary multiplicity, so every instance
− methodB1
has it’s own item. This item is listed without an underlining.
+ methodB2
On the other hand there are items which are related to the class. This item
Figure 2.12: Item Types
are accessed using the class name as a prefix and not the instance name.
A class item one once exists in the application. A class related item is listed in the UML class diagram
with an underlining.

Class 1
Figure 2.13 shows a aggregation and a composition. An
List A aggregation is drawn by a white filled rhombus. An com-
List B position is drawn by a black filled rhombus. Aggregation
and compositions describe a container or a list of several
Method 1
instances of an object, which are members of a main class.
If for example a profile consists of several parts, the parts
can be described as an composition, if a part only exists
3..* sorted 1 random
within a profile. If a part exists also without a profile, the
Class A Class B parts are described within the profile with an aggregation.

Attribute A1 Attribute B1 At the ends of the connecting lines the multiplicities are
Attribute A2 Attribute B2
noted. The multiplicity gives the range of referenced in-
stances in the form from..to. For the Class A we have 2
Method A Method B up to infinite instances in an composition, therefor at the
end of the line we can not have a multiplicity of zero. In
Figure 2.13: A UML Diagram for a Composi-
tion and an Aggregation our example we have exactly one instance of the class 1.
On the other hand Class B is referred to Class 1 within an
aggregation. In our example on instance of Class B can be
reverenced by an undefined number of instances of Class 1. This is shown by the * icon. On the other
hand the class 1 references at least on instance of the Class B. Otherwise the number of references is
arbitrary. This is also shown by the * icon.

E. Baeck
2.19. OOP WITH CLASSES Page 55

2.19.2 Implementation of Classes in Python

Classes are implemented in Python with the keyword ClassX ClassY


class. The class key is followed by the name of the
class, which we find in the upper section of the class dia- + attributeX1 + attributeY1
gram. If a class inherits from other classes, it’s called sub- − attributeX2 − attributeY2
class. Then the subclass’s name is followed by a comma sep-
− methodX1 − methodY1
arated list of classes to inherit from. This classes are called
+ methodX2 + methodY2
base classes, superclasses or parent classes. So we have the
following syntax, if your class ClassZ should inherit from
ClassX and ClassY. The implementation of the class is
indented like a function’s code. ClassZ
1 class ClassZ(ClassX, ClassY):
+ attributeZ1
2 ..
3 class implementation − attributeZ2
4 ..
+ methodZ1
+ methodZ2

Figure 2.14: Some Classes


2.19.2.1 Class Constructor

The constructor of a class is called if an instance is created. A constructor is a function, i.e. method of
a class, having a fixed name. The constructor defines the interface to the class, if an instance should be
created.

The following code shows the constructor of class ClassZ and how to create it’s instance. The name
of the constructor is __init__. The leading two underscores set the constructor to private, i.e. this
method is hidden and is not allowed to call from outside. We also should notice, that an instance reference
in Python is passed with the key self. This parameter, the first in the implementation, is not explicitly
passed (see line 9). Only the the real parameters should be passed in the call. A further thing to mention
is, that instance attributes are only created, if an assignment is done.17
1 class ClassZ(ClassX, ClassY):
2

3 def __init__(self,par1,par2):
4 self.attributeZ1 = par1
5 self.__attributeZ1 = par2
6

7 ..
8

9 c = ClassZ(1,2)

17
In a compiled language like C++ or FORTRAN a variable, an attribute or a method are created in compile time, they are
available already at start up.

8.5.2018
Page 56 Analysis of Structures - SS 15

2.19.2.2 Class Destructor

The destructor of a class is called if an instance is deleted with the del command, which means is freed
from the memory. The destructor is a functions, i.e. method of a class, having a fixed name.

The following code shows the destructor of class ClassZ. The name of the destructor is __del__. The
leading two underscores set the destructor to private, i.e. this method is hidden and is not allowed to call
from outside. We also should notice, that an instance reference in Python is passed with the key self.
The destructor only has one parameter the instance reference. The example shows like before how we
create an instance of the class ClassZ and how to free it. If we free this instance, the instance’s method
__del__ is executed and gives us a goodby.
1 class ClassZ(ClassX, ClassY):
2

3 ...
4

5 def __del__(self):
6 print "goodby!"
7

8 ..
9

10 c = ClassZ(1,2)
11 del c

We should consider, that destructors can not handle exceptions.

E. Baeck
2.19. OOP WITH CLASSES Page 57

2.19.3 Implementation of a Time Stack Class

In section 2.17 we have discussed a little program which implements a time checker using a stack con-
tainer. We can implement this problem in a much more clearer version, if we do it in terms of the OOP
approach. The class TimeCheck, which is introduced, encapsulates the time stack list and the log files
name as attributes and the following methods.

• set reads the actual time with the datetime.now() and pushes it onto the time stack.

• get reads the actual time with the datetime.now(), pops the the last time object from the stack and
calculates the timespan. The timespan is optionally printed into the console window or into a log
file.

• getTime calculates the seconds in floats form the passed timedelta object.

The main program, which is used to discuss the class follows the steps of the classical implementation
of the problem discussed in section 2.17. We first create an empty tuple and an empty list. Than we
create the TimeCheck instance18 simple by assigning it’s name to a variable (s = TimeCheck()). To
push a time object onto the stack, we call the class’s member function Set. So, if we want to check the
performance of a code, we first call the Set method and after having executed the code, we call the Get
method. The Get method will print the comment and will return the used seconds of execution time in
floats. The simplest kind of an implementation is the implementation in the file of the main program.
This you can see in the following example.

A UML diagram of the class TimeCheck is given in figure 2.15.

TimeCheck

+ self. log: name of the log file The class TimeCheck contents all the data and
+ self. stack: stack list functions to use a time stack and to get the
time-span information in a proper float format.
+ self. init (..): contructor
The class is able to present a formated output
+ self.set(..): push a time of the measured time-spans.
+ self.getTime(..): calculate seconds
+ self.get(..): pop a time

Figure 2.15: UML-Diagram of the TimeCheck Class

18
A physical created object in memory of a class is called instance of a class.

8.5.2018
Page 58 Analysis of Structures - SS 15

Listing 2.16: Implementation of a Performance-Checker-Class

1 ’’’
2 Class to investigate the timespan, to measure the performance
3 by implementing a time stack container
4 ’’’
5 # - module - member alias
6 from datetime import datetime as time # we need the datetime package
7

8 class TimeCheck(): # class name


9

10 # constructor
11 def __init__(self,log = "timestack.log"):
12 self._stack = [] # empty list
13 self._log = log # set the logfile’s name
14

15 # set up the actual time and push it onto the stack


16 def set(self):
17 self._stack.append(time.now())
18

19 # calculate the timespan in float


20 def getTime(self,T):
21 s = float(T.microseconds)/1.e6 +float(T.seconds) +float(T.days)*24.*60.*60.
22 return s
23

24 # calculate the timespan with a stack object


25 def get(self,text = ""):
26

27 # get the stack length


28 items = len(self._stack)
29

30 # assert(items > 0) # to assert, that there is a time object


31 # stored in stack (alternative solution)
32 if items < 1:
33 print "*** Error: timestack empty!"
34 return
35

36 tStart = self._stack.pop() # pop the time object from the stack


37 tEnd = time.now() # get the end time
38 tDel = self.getTime(tEnd -tStart) # calculate the timedelta in floats
39

40 # we have an maximal indent of 6 columns


41 indent = 6
42 space1 = "" # leading characters for level indent
43 space2 = "" # trailed characters to aling the comment
44

45 # set up indent text


46 for i in range(items-1): space1 += "." # fill in dots
47 for i in range(indent -items): space2 += " " # fill in white spaces
48

49 # print comment if given


50 if len(text) > 0:
51 textout = "%s %8.3f%s: %s" % (space1,tDel,space2,text)
52

53 # comment to the screen


54 print textout

E. Baeck
2.19. OOP WITH CLASSES Page 59

55

56 # logging the comment


57 f = file(self._log,"a")
58 f.write(textout + "\n")
59 f.close()
60

61 return tDel # return the seconds in floats


62

63 # application of the TimeCheck class


64 print ">> Start.."
65 nX = 50000
66 T = () # empty tuple
67 L = [] # empty list
68

69 # create the timecheck object


70 s = TimeCheck()
71

72 # check the total performance


73 s.set()
74

75 # check the performance of the tuples


76 s.set()
77 for i in range(nX): T+= (i,)
78 s.get("Creating %d item tuple." % nX)
79

80 # check the performance of the list


81 s.set()
82 for i in range(nX): L+= [i]
83 s.get("Creating %d item list." % nX)
84

85 # check the whole performance


86 s.get("total time")

If we run the program, we see that two time stamps are indented with one dot. This timestamps are set
for inner performance measurements, that is the time-stamp for the creation of the tuple and after that
the time-stamp for the the creation of the list. The last time-stamp shows the total execution time and is
created by the first push, i.e. the first Set call and the last pop, i.e. the last Get call.
1 >> Start..
2 . 8.282 : Creating 50000 item tuple.
3 . 0.016 : Creating 50000 item list.
4 8.329 : total time

8.5.2018
Page 60 Analysis of Structures - SS 15

E. Baeck
3

Python Projects

3.1 Newton, Step2

We have discussed the newton’s scheme in section 2.10. Within this section the project’s code will be
extended by plot features. The function and it’s derivative as well as the path of iteration will be plotted
using the pylab package.

The following features are added to the implementation of newton’s scheme.

1. Import the pylab package.

2. The function getFunctionValues creates a list of the function values for the plot routine.

3. The function getFunctionDerivativeValues creates a list of the function’ derivative values for the
plot routine.

4. The function newton will be extended by two lists, which should store the values of the iteration
path. After each iteration step, the x-value and it’s function value are stored for later drawings.

61
Page 62 Analysis of Structures - SS 15

A disadvantage of the first implementation in section 2.13.2 is, that the algorithm will fail, if a vanishing
slope is found. With a simple work around we can solve this problem. We simple step aside as long as a
minimum slope value is reached. The flow chart is given in figure 3.1.

Start

Initializing:
x = x0 ; i = 0;

yes
i ≥ imax NO ROOT! Stop

no

F x = f (x)

yes
|F x| ≤  ROOT: x Stop

no
F s = f 0 (x)

yes x = x+∆
|F s| ≤ 
i = i+1

no
Fx
x = x− Fs

i = i+1

Figure 3.1: Flow Chart for a Slope Insensitive Newton Implementation

Listing 3.1: Implementation of Newton’s-Algorithm, plotting the results

1 import pylab # plot a little (not used in this step)


2 from math import fabs as abs # import the fabs as abs
3

4 # implementation of the function of interest


5 def myF(x):
6 return x**2 -1.
7 # return x**10 -1. # check the extrem case
8 # return 0. # check the constant
9

10 # calculating the derivative


11 def fs(f,x,h=1.e-6):
12 h = float(h)

E. Baeck
3.1. NEWTON, STEP2 Page 63

13 x = float(x)
14 return (f(x+0.5*h) - f(x-0.5*h))/h
15

16 # implementation of a newton algorithm


17 def newton(f,x0,e=1.e-10,h=1.e-6,imax=1000):
18

19 error = None # initialize the error code with None


20

21 h = float(h) # we need some floats


22 e = float(e)
23 x1= float(x0) # x to interate
24 f1= None # initialize it for return
25

26 xL= [] # list for x-values


27 yL= [] # list for the function values for x
28 sL= [] # list for the slope values for x
29

30 i = 0 # iteration counter
31 while True:
32

33 # available iterations exceeded


34 if i >= imax:
35 error = "*** Error: no root found!"
36 break
37

38 # checking for roots


39 f0 = f(x1) # function’s value
40 xL.append(x1) # save x Value
41 yL.append(f0) # save the functions value
42 if abs(f0) < e:
43 f1 = fs(f,x1,h)
44 sL.append(f1) # save the last nslope value
45 break
46

47 # calculating the derivative


48 f1 = fs(f,x1,h)
49 sL.append(f1) # save the slope value
50

51 if abs(f1) < e:
52 x1 += 1.e2*h # little step aside
53 i += 1 # avoid dying with a vanishing slope
54 continue
55

56 # calculating the values for next iteration


57 x1 -= f0/f1
58

59 # increment the iteration counter


60 i+=1
61

62 # return the actual position, the function value


63 # and the functions slope, the number of performed
64 # iterations and the error code.
65 # index 0 1 2 3 4 5 6 7
66 return (x1,f0,f1,i,error,xL,yL,sL)
67

68 # creating a list of function values for a x-list

8.5.2018
Page 64 Analysis of Structures - SS 15

69 def getFunctionValues(xL,f):
70 yL = []
71 for x in xL:
72 y = f(x)
73 yL.append(y) # yL += [y]
74

75 return yL
76

77 # create a list of function’ derivative values


78 def getFunctionDerivateValues(xL,f):
79 yL = []
80 for x in xL:
81 y = fs(f,x)
82 yL.append(y)
83

84 return yL
85

86 # parameters of the problem


87 xl = -5. # lower bound
88 xu = 5. # upper bound
89 xc = 0.5 # increment
90

91 # visalization of the function and it’s derivative


92 # create the x-List
93 xList = pylab.arange(xl,xu,xc)
94

95 # create list of function’s values


96 yList = getFunctionValues(xList,Myf)
97 pylab.plot(xList,yList,’b’)
98

99 # create list of function’s derivative values


100 ysList = getFunctionDerivateValues(xList,Myf)
101 pylab.plot(xList,ysList,’g’)
102

103 # the function newton is called with standard parameters


104 # we pass the function of interest and a supposed start
105 # position
106 x0 = 0.
107 res = newton(Myf,x0)
108

109 # the returned tuple is printed into the console window


110 print "\n> next run"
111 print "x0 = %f" % x0 # starting value
112 print "x = %f" % res[0] # last x value
113 print "f(x) = %f" % res[1] # last f(x) value
114 if res[2] is not None:
115 print "f’(x) = %f" % res[2] # last f’(x) value
116 print "i = %d" % res[3] # number of iterations
117 if res[4] is not None:
118 print "%s" % res[4] # error message
119 if len(res[5]) > 0:
120 print "--------------x -----------f(x) ----------f’(x)"
121 for i in range(len(res[5])):
122 print "%15.6e %15.6e %15.6e" % (res[5][i],res[6][i],res[7][i])
123 print "--- end of code ---\n"
124

E. Baeck
3.1. NEWTON, STEP2 Page 65

125 # plot the iteration path


126 pylab.plot(res[5],res[6],’rp’)
127

128 # output of plot data


129 pylab.grid(True) # show grid lines
130 pylab.savefig("NewtonStep2.png")
131

132 # - show plot data


133 pylab.show()

After the output lists are created the lists are passed to the plot post-processor by the plot method of
PyLab. After enabling the grid the plot data are written in a graphic file and are visualized in the PyLab
viewer application.

Figure 3.2 shows the iteration path for the equation f (x) = x2 − 1 with an starting value of 4 with red
dots.

Figure 3.2: Newton’s Iteration Path starting with 4

If we would start our calculation with a starting value of 0, we know that the slope will vanish. If we
now step aside with the precision of our numerical derivative, we will get the following iteration path.
1 x0 = 0.000000
2 x = 1.000000
3 f(x) = 0.000000
4 f’(x) = 2.000000
5 i = 18
6 --------------x -----------f(x) ----------f’(x)
7 0.000000e+00 -1.000000e+00 0.000000e+00
8 1.000000e-04 -1.000000e+00 2.000000e-04
9 5.000000e+03 2.500000e+07 1.000000e+04
10 2.500001e+03 6.250002e+06 5.000003e+03
11 1.250001e+03 1.562501e+06 2.500002e+03
12 6.250008e+02 3.906250e+05 1.250002e+03

8.5.2018
Page 66 Analysis of Structures - SS 15

13 3.125012e+02 9.765602e+04 6.250025e+02


14 1.562522e+02 2.441375e+04 3.125044e+02
15 7.812931e+01 6.103189e+03 1.562586e+02
16 3.907105e+01 1.525547e+03 7.814211e+01
17 1.954832e+01 3.811370e+02 3.909665e+01
18 9.799739e+00 9.503489e+01 1.959948e+01
19 4.950891e+00 2.351133e+01 9.901783e+00
20 2.576438e+00 5.638031e+00 5.152875e+00
21 1.482285e+00 1.197170e+00 2.964570e+00
22 1.078460e+00 1.630751e-01 2.156919e+00
23 1.002854e+00 5.716204e-03 2.005708e+00
24 1.000004e+00 8.122320e-06 2.000008e+00
25 1.000000e+00 1.649347e-11 2.000000e+00
26 --- end of code ---

We see that due to the very small slope, the resulting jump in the iteration is very large, so that we need
some iterations more to get the root. If we would do this on a very flat function like f (x) = x1 0 − 1, we
have to count the steps, to avoid the programs hanging. The function is as flat that the number of small
steps to get out of the trap will increase to a nearly infinite number.

Figure 3.2 shows the iteration path for the equation f (x) = x2 − 1 with an starting value of 0 with red
dots.

Figure 3.3: Newton’s Iteration Path starting vom 0

E. Baeck
3.2. PROFILES, THIN WALLED APPROACH Page 67

3.2 Profiles, Thin Walled Approach

In this section we will implement a class hierarchy to model a profile’s data. We will implement logging
into file and screen in a common base class and we will implement the thin walled approach to analyze
and calculate the profile’s section properties.

Applying the Thin Walled Approximation every part of a section will be approximated by a line with a
given thickness. This approach is similar to the approach modeling a three dimensional shell structure.
Hereby we use shell elements, i.e. faces, with a given thickness. The lines like the shell elements in FE
will connect nodes or points.

So if we want to build up a calculation model for our thin-walled section, we need something like lines
and points. Lines are called Elments and Points are called Nodes like in the case of programs. In our
case we introduce two classes.

• The class Node describes the contour point of elements. In our case we have the end points of
lines in two dimensions.

• The class Element describes the connection between nodes. In our case we connect points with
lines so that we have to specify the thickness of the line, ie. the connection.

Further we introduce a class Base, which should content all common features. A general profile then
will be described by the class Profile. This class can therefore be considered as a container for our points
and lines as well as the class which should perform all calculations. To show the power of inheritance we
introduce a derived profile class, which is called UProfile. This class will describe all U-profiles with
their geometric parameters. Based on our class Profile this class will be able to calculate all section
values based on the given parameter set. All details, i.e. points and lines are encapsulated in it’s base
class.

3.2.1 A General Base Class

If we want to use the code of an existing class within a new class, we can inherit this old class and use
it as a base class. That means, that the new class contents also the attributes and the methods of the old
one. A base class is used in the class statement as an argument. A class can inherit more than one class.
In our case everything is derived from our general base class called Base.

The class Base should content logging for all classes. This class should also be able to count all cre-
ated instances of the developed application. The output method for all classes should be the method
AppendLog, i.e. this method will be inherited by all classes of our project. The classes UML diagram
is given in figure 3.4.

The class Base counts the instances using the global class attribute __count. A common logging
method is implemented. So the name of the log file is implemented as a class method (not an instance
method) __log. The method appendLog is implemented as a general logging function. The actual
time is called an copied as heading for our logging comment. Then the completed logging text is written
into the log file and into the screen.

8.5.2018
Page 68 Analysis of Structures - SS 15

Base

− log: global log file name The class Base contents common
− count: global instance counter features which are used in every
class.
− self. init (..): constructor
+ self.appendLog(..): write to log

Figure 3.4: The Base Class of all TWD Classes

The implementation of the class Base is given in listing 3.2.

Listing 3.2: Implementation of a Base-Class

1 ’’’
2 the Base class of all TWA-classes
3 ’’’
4 # import some packages
5 # |package
6 # | | select the item to import
7 # | | | alias name
8 from datetime import datetime as time
9

10 class Base:
11 __log = "profiles.log" # class attribut, type private
12 __count = 0 # class attribut, instance counter
13

14 # construtor
15 # |instance pointer
16 # | |optional parameter
17 def __init__(self,log = ""):
18 Base.__count += 1 # increment the counter
19 if len(log) > 0: Base.__log = log # set a new log-file name
20

21 # print the instance counter value


22 self.appendLog(">> instance %d created!" % Base.__count)
23

24 # print a message into the log file and to the console


25 # | instance pointer
26 # | | text to print
27 def appendLog(self,text):
28 t = time.now() # get the time
29 tstamp = "%2.2d.%2.2d.%2.2d |" % (t.hour,t.minute,t.second)
30 textout = tstamp + text # text to print
31

32 # use the file object to print with the append mode "a"
33 f = file(Base.__log,"a")
34 f.write(textout+"\n") # write text
35

36 print textout
37

38 # destructor
39 def __del__(self):
40 self.appendLog("instance %d deleted" % Base.__count)
41 Base.__count -= 1 # decrement the counter

E. Baeck
3.2. PROFILES, THIN WALLED APPROACH Page 69

3.2.2 A Node Class

The class Node only has the attributes of the points number and it’s coordinates. The coordinates are
stored within a list. If we do this, we simply can extend this object to a three dimensional application.
Besides the constructor we will implement a method list, which should be able to print the instances
data to a given output stream. This method will use our method appendLog of the base class. The
classes UML diagram is given in figure 3.5.

Base
Will provide appendLog

Node

+ no: node number The class Node contents the co-


+ x[]: List for point coordinates ordinates and the number of a
profile’s node.
− self. init (..): constructor
+ self.list(..): print node data

Figure 3.5: UML-Diagram for a Node Class

The implementation of the class Node is given in listing 3.3.

Listing 3.3: Implementation of a Node-Class

1 __author__ = ’baeck’
2

3 # forced reload
4 import Base
5 reload(Base)
6

7 # module item
8 from Base import Base
9

10 # class to describe a profile node


11 class Node(Base):
12

13 # constructor
14 # self pointer
15 # number and the coordinates
16 def __init__(self,no,x,y):
17

18 # run the constructor of the Base class


19 Base.__init__(self)
20

21 try:
22 self._no = int(no)
23 self._x = [float(x),float(y)]
24 except:
25 raise "*** error: invalid input!"
26

27 # destructor

8.5.2018
Page 70 Analysis of Structures - SS 15

28 def __del__(self):
29 pass
30

31 # list the node content


32 def list(self):
33 self.appendLog("node %d, x = %10.4f, y = %10.4f" % \
34 (self._no,self._x[0],self._x[1]))

3.2.3 Testing the Node Class

In our testing environment we simple import the Node module. Than we create a Node instance and list
it’s data. After that we delete the instance and we try to print it again.

The implementation of the testing environment is given in listing 3.4.

Listing 3.4: Implementation of a Node-Testing Environment

1 ’’’
2 checking the Node class
3 ’’’
4 import Node # we have to be sure
5 reload(Node) # that we check the current file
6

7 from Node import Node # import the Node class


8

9 n = Node(3,1.,2.) # we create a point


10 n.listData() # and list it’s value
11

12 # delete the instance


13 print n # let’s print the Nodes address
14 del n # and than we delete the instance
15 print n # try to print it again

The output of our test application is given in the following code. We see, that the Base class constructor
shows, that a new instance is created. The next line shows the output of Node’s list method followed
by the simple instance print, which shows the address of the instance. Than the instance is explicitly
deleted, so that the destructor of the Base class shows that one instance is deleted. Because the address
of the instance after deleting is invalid, the program will crash with a trace back message. The line (line
15) is given and the message shows us, that at this moment there is no valid variable called p.
1 15.49.12 |>> instance 1 created!
2 15.49.12 | point 3, y = 1.000, z = 2.000
3 <Node.Node instance at 0x031AE300>
4 15.49.12 |instance 1 deleted
5 Traceback (most recent call last):
6 File "C:\Python27\Lib\site-packages\Pythonwin\pywin\framework\scriptutils.py",
7 line 326, in RunScript
8 exec codeObject in __main__.__dict__
9 File "C:\UniDue\CM\Cm-AoS\AOS-BookOfExamples\Py\Code\Profiles\NodeApp.py",
10 line 15, in <module>
11 print p # try to print it again
12 NameError: name ’p’ is not defined

E. Baeck
3.2. PROFILES, THIN WALLED APPROACH Page 71

3.2.4 An Element Class

The class Element will describe the connection between points and will describe further the type of
connection. In the case of a line we will have the line’s thickness. Because in our case the properties of
the profile, i.e. it’s area and moments, are given by the sum over the element’s contribution (see section
B), we put the code to calculate this properties into the element’s class. If we do so, the element must
know everything about it’s points, i.e. the numbers of the points are not sufficient to have success. So
we store the point’s instance pointers and not there number in our element. The classes UML diagram is
given in figure 3.6.

The element can be considered as a container for Node instance pointers too. This is shown within the
diagram using the composition link to the class Node. The cardinality in our case is exactly two. If we
would introduce faces too for the thick-walled case, the cardinality can also be greater then two.

Base

Element

+ no: element number The class Element contents the


element’s point data.
+ n[]: list of point instance pointers
+ t: line’s thickness

− self. init (..): constructor


+ self.getL(): get line’s length Node
+ self.getA(): get area
+ no: node number
+ self.getS(): get static moments
+ x[]: List for point coordinates
+ self.getI(): get moments of inertia
+ self.list(..): print element data − self. init (..): constructor
+ self.list(..): print node data

2..*

Figure 3.6: UML-Diagram for a Element Class

8.5.2018
Page 72 Analysis of Structures - SS 15

The implementation of the class Element is given in listing 3.5.

Listing 3.5: Implementation of an Element-Class

1 __author__ = ’baeck’
2 ’’’
3 implementation of an element class
4 ’’’
5 import Base
6 reload(Base)
7

8 # module item
9 from Base import Base
10

11 # | inherit the Base class


12 class Element(Base):
13

14 # constructor
15 def __init__(self,no,node1,node2,t):
16

17 Base.__init__(self)
18

19 self._no = no
20 self._n = [node1,node2]
21 self._t = t
22

23 # calculate projected length x,y


24 # i: dimension
25 def delX(self,i):
26 return self._n[1]._x[i] - self._n[0]._x[i]
27

28 # calculate the length of the element


29 def getL(self):
30 return (self.delX(0)**2 + self.delX(1)**2)**0.5
31

32 # calculate the element’s area


33 def getA(self):
34 return (self.getL()*self._t)
35

36 # calculate the center coordinates of an element


37 # i: dimension (y,z)
38 def getC(self,i):
39 return ( (self._n[1]._x[i] + self._n[0]._x[i])/2. )
40

41 # calculate the static moment of the element


42 # i: dimension (y,z)
43 def getS(self,i):
44 return ( self.getC((i+1)%2)*self.getA())
45

46 # calculate the moment of inertia


47 # i: dimension (yy,zz,yz)
48 def getI(self,i):
49 if i < 2:
50 j = (i+1)%2
51 return ( (self.delX(j)**2/12. + self.getC(j)**2)*self.getA() )
52 else:

E. Baeck
3.2. PROFILES, THIN WALLED APPROACH Page 73

53 return ( (self.delX(0)*self.delX(1)/12. + self.getC(0)*self.getC(1))


54 *self.getA() )
55

56 # list the elements data


57 def list(self):
58 self.appendLog("element %d: nodes: %d %d, t = %.2f, A = %.1f" %
59 (self._no, self._n[0]._no, self._n[1]._no, self._t,self.getA() ))
60 self.appendLog(" center..............: %10.3e %10.3e" %
61 (self.getC(0),self.getC(1)))
62 self.appendLog(" static moments......: %10.3e %10.3e" %
63 (self.getS(0),self.getS(1)))
64 self.appendLog(" moments.of inertia..: %10.3e %10.3e %10.3e" %
65 (self.getI(0),self.getI(1),self.getI(2)))

3.2.5 Testing the Element Class

In our testing environment we simple import the Element as well as the Point module. Than we create
two Node instances, which will describe the end points of our line. Then the Element instance is
created, passing the two Node instance pointer and the lines thickness. After that we list the element’s
data and delete it.

The implementation of the testing environment is given in listing 3.6.

Listing 3.6: Implementation of a Element-Testing Environment

1 ’’’
2 check the Element class
3 ’’’
4 import Element # do this if you want to sure
5 reload(Element) # that the module file is the currend one
6

7 from Element import Element # of course we need the Element class


8 from Node import Node # and the Node class too
9

10 h = 200.
11 t = 5. # thickness
12

13 # create the points


14 n1 = Node(3,0.,-h/2.)
15 n2 = Node(2,0., h/2.)
16

17 # create the element


18 e1 = Element(2,n1,n2,t)
19

20 # print the element’s data


21 e1.list()
22

23 # delete instances
24 del n1
25 del n2
26 del e1

The following output shows, that 3 instances (2 nodes and 1 element) are created. We see the element’s
data, i.e. the node numbers (3,2) and the thickness (5.0). The length and die area are calculated by the

8.5.2018
Page 74 Analysis of Structures - SS 15

call of the according methods.


1 >>> 15.57.08 |>> instance 1 created!
2 15.57.08 |>> instance 2 created!
3 15.57.08 |>> instance 3 created!
4 15.57.08 | element 2, A= 3, B= 2, t= 5.000 L= 200.000 A= 1000.000
5 15.57.08 | center............: 0.000 0.000
6 15.57.08 | static moments....: 0.000e+00 0.000e+00
7 15.57.08 | moments of inertia: 3.333e+06 0.000e+00 0.000e+00
8 15.57.08 | node 3, y = 0.000, z = -100.000
9 15.57.08 | node 2, y = 0.000, z = 100.000
10 15.57.08 |instance 3 deleted
11 15.57.08 |instance 2 deleted
12 15.57.08 |instance 1 deleted

The element’s length obviously is 200 and the area 1000. If we apply the well known formula for the
3 3
moment of inertia of an rectangle I = h12·w = 20012 ·5 = 3.33 · 106 we get the value in the listing. So it
seems to be ok.

E. Baeck
3.2. PROFILES, THIN WALLED APPROACH Page 75

3.2.6 A General Profile Class

So if we want to develop a software, which is able to calculate the profile’s section properties like it’s
area, moment of inertia and so on, we can consequently split up the problem in general and specific
parts. So we start with the data and the functions of a general object. This data is collected in a class
which we call Base. So if we want to describe a wide range of profile types, then we should think about
the profile’s common features. Every profile has a name and therefore this name is a common feature.
This common features are collected in a general profile class which is called Profile. If we want to
handle a specific profile type given by a set of parameters like an U-profile ore a tube profile, we collect
the specific type dependent features in the classes UProfile and TubeProfile, which are obviously the
parameters describing the profile’s geometry.

The class Profile now contents common profile features. One of them is the profile’s name. Note,
if we inherit a class from a base class, we have to call the base class’s constructor method. Every
attribute and every method of the base class is now available. A second feature of the Profile class is
the implementation of the thin walled model. Therefore we introduce an Element container using the
AList class. With a specific method we insert an Element instance into the container. To calculate the
section values of the created thin walled model we introduce some methods, which calculate the global
section values summing up all element values and transforming them into the desired coordinate system.

At least we introduce a little viewing method, which should create a png picture file of the profile and
should optionally start the pylab viewer tool. To be sure, that the environment supports the Tkinter
package1 , which is used by the viewer, we import the package using a try: ... except: handler.
At the end of the view method we should close the plot, to avoid a memory effect.

Profile

+ self. name: The profile’s name


+ self. elem: Element container

− self. init (..): constructor The class Profile contents all


common features of a profile
+ self.list(..): List profiles values
especially the containers for the
+ self.addElement(..): insert a new Element Points and Lines of shape modell
+ self.getResults(): calculate section values
− self.getPValues(): transform the moment of inertia
− self.pTrans(): principal axis transformation
+ self.view(..): views a profile plot

Figure 3.7: The general Profile Class

A U-profile is described within the frame of the TWA by it’s height and width as well as by the thicknesses
of it’s web and flange. So we need 4 floats to do this. It’s UML diagram is given in figure 3.8.

1
We will see later trying to apply our package Profiles in the frame of the Abaqus scripting, that we will get problems,
because the Abaqus environment is not developed with Tkinter.

8.5.2018
Page 76 Analysis of Structures - SS 15

UProfile

+ self. h: height
The class UProfile contents the
+ self. w: with special features of an U-Profile,
+ self. s: web thickness i.e. the geometric parameters.
+ self. t: flange thickness The class will be inherit the Pro-
file class and will have the feature
− self. init (..): constructor to create this profile with an U
+ self.list(..): list profiles values geometry.
+ self.check(): check input values
+ self.create(..): create thin walled model

Figure 3.8: The U-Profile Class

A tube-profile is described within the frame of the TWA by it’s diameter and it’s thickness. So we need
only 2 floats to do this. It’s UML diagram is given in figure 3.9.

TubeProfile

+ self. d: diameter
The class TubeProfile contents
+ self. t: thickness
the special features of a Tube-
− self. init (..): constructor Profile, especially the geometric
+ self.list(..): list profiles values parameters

+ self.check(): check input values


+ self.create(..): create thin walled model

Figure 3.9: The Tube-Profile Class

To hold the desired Element instances we implement a slightly modified list class, which should
work like an array with a well defined index access (see section 3.2.7). If we would use a standard list
class, we would get problems if we want to insert an object at a position outside the list range. Then a
standard list object simply appends this object as a new item at the tail of the list and we would loose the
correct index position. So we implement a new index save Add method, which checks the list length and
if necessary enlarges the list up to the desired index position.

The implementation of the class Profile is given in listing 3.7.

Listing 3.7: Implementation of an Profile-Class

1 # -*- coding: utf-8 -*-


2

3 __author__ = ’baeck’
4 ’’’
5 Profile class to calculate section values
6 with the thinwalled approximation
7 ’’’
8

9 from Base import Base


10 from AList import AList
11

E. Baeck
3.2. PROFILES, THIN WALLED APPROACH Page 77

12 class Profile(Base):
13

14 # constructor
15 def __init__(self,name):
16

17 Base.__init__(self)
18

19 self._name = name # profile name


20 self._elem = AList() # element container
21

22 # result data
23 self._a = 0.
24 self._s = [0.,0.] # static moments
25 self._e = [0.,0.] # center of mass coordinates
26 self._iu = [0.,0.,0.] # moment of intertia in user coordinates
27 self._ic = [0.,0.,0.] # moment of intertia in center of mass coordinates
28 self._ip = [0.,0.] # moment of intertia in principal coordinates
29 self._alp = 0. # rotation angle
30

31 # add an element into the profile container


32 def addElement(self,e):
33 self._elem.add(e._no,e)
34

35 # caculate the sections values of the profile


36 def getResults(self):
37

38 elements = 0 # element counter


39

40 # sum up all element contributions


41 for e in self._elem:
42

43 # only for available elements!


44 if e is not None:
45

46 # area
47 self._a += e.getA()
48

49 # static moment
50 for i in range(2): # [0],[1]
51 self._s[i] += e.getS(i)
52

53 # moment of inertia
54 for i in range(3):
55 self._iu[i] += e.getI(i)
56

57 elements += 1 # count the elements


58

59 if elements < 1: raise Exception("error: no elements found!")


60

61 # calculate the center of mass coordinates


62 self._e[0] = self._s[1]/self._a
63 self._e[1] = self._s[0]/self._a
64

65 # calculate the princial values


66 self.getPValues()
67

8.5.2018
Page 78 Analysis of Structures - SS 15

68 return (self._a,self._s,self._ip,self._alp)
69

70 # calculate the principal values


71 # shift and rotate!
72 def getPValues(self):
73 import math
74

75 # shift the moment of inertia into the center of mass cs


76 self._ic[0] = self._iu[0] - self._e[1]*self._e[1]*self._a
77 self._ic[1] = self._iu[1] - self._e[0]*self._e[0]*self._a
78 self._ic[2] = self._iu[2] - self._e[0]*self._e[1]*self._a
79

80 # introduce some helpers


81 idel = self._ic[0] - self._ic[1]
82 isum = self._ic[0] + self._ic[1]
83 isqr = math.sqrt(idel*idel + 4.*self._ic[2]*self._ic[2])
84

85 # calculate the principal values


86 self._ip[0] = 0.5*(isum + isqr)
87 self._ip[1] = 0.5*(isum - isqr)
88

89 # calculate the rotation angle


90 self._alp = 0.5*math.atan2(-2.*self._ic[2],idel)
91

92 # get angle value in degrees


93 self._alp *= 45./math.atan(1.)
94

95 # list the profile’s data


96 def listData(self):
97 self.appendLog("name..................: %s" % self._name)
98 self.appendLog("area..................: %10.2f cmˆ2" % (self._a/1.e2,))
99 self.appendLog("center of mass .......: %10.2f %10.2f cm" % \
100 (self._e[0]/1.e1,self._e[1]/1.e1))
101 self.appendLog("static moments .......: %10.2f %10.2f cmˆ3" % \
102 (self._s[0]/1.e3,self._s[1]/1.e3))
103 self.appendLog("moment of inertia uc: %10.2f %10.2f %10.2f cmˆ4" % \
104 (self._iu[0]/1.e4,self._iu[1]/1.e4,self._iu[2]/1.e4))
105 self.appendLog("moment of inertia cc: %10.2f %10.2f %10.2f cmˆ4" % \
106 (self._ic[0]/1.e4,self._ic[1]/1.e4,self._ic[2]/1.e4))
107 self.appendLog("moment of inertia pc: %10.2f %10.2f cmˆ4" % \
108 (self._ip[0]/1.e4,self._ip[1]/1.e4))
109 self.appendLog("rotation angle : %10.2f " % self._alp)
110

111 # print a picture of the profile geometry


112 def view(self,viewer = True):
113

114 try:
115 import pylab
116 except:
117 self.appendLog("error: pylab not intalled!")
118 return
119

120

121 # list of lines. every element -> a line


122 lines = []
123

E. Baeck
3.2. PROFILES, THIN WALLED APPROACH Page 79

124 # over all elements


125 for e in self._elem:
126 if e is not None:
127 x1 = e._n[0]._x[0]
128 y1 = e._n[0]._x[1]
129 x2 = e._n[1]._x[0]
130 y2 = e._n[1]._x[1]
131

132 # add the line data into the list


133 lines += [ [ [x1,x2], [y1,y2] ], ]
134 # --- a line ---------
135

136 # plot the lines


137 for line in lines:
138 pylab.plot(line[0],line[1],’b’) # b: blue
139

140 # plot the lines nodes


141 for line in lines:
142 pylab.plot(line[0],line[1],’rp’) # r: red p: point
143

144 # plot the title


145 pylab.title(self._name)
146

147 # plot it into a png-file


148 pylab.savefig(self._name + ".png")
149

150 # show viewer


151 if viewer: pylab.show()
152

153 # close the pylab


154 pylab.close()

3.2.7 The AList Class

In our implementation of the Profile class we want to work with lists giving an array like feeling, i.e.
in every case an insertion with a given index has to be like an assignment to an array slot. If we now use
Pythons buildin list class, we will see, that if the index is greater than the upper-bound, the item to be
inserted will be appended. If so, we will loose the strict array behavior of our container. The solution is
very simple. We take the build-in list class and derive our own list object called AList.

The only thing we have to add to the build-in list will be an index save add method. On the other
hand it would be very comfortable, if we implement a list method, which is able to print every thing
inside the container in it’s desired format. The implementation of the last is very simple due to the
polymorphism strategy of OOP, i.e. an objects list method can be called without implementing a case
like filtering. This assignment is done automatically, because the general list method of an object is
projected onto the specific of the object. So every object will have it’s own list method. In our case
we have a Node and an Element object. Both of them, we have seen, have their own list method,
which then automatically is called.

The UML diagram of the AList class is given in figure 3.10.

The implementation of the class AList is given in listing 3.8.

8.5.2018
Page 80 Analysis of Structures - SS 15

Base list Python’s build-in


list container

AList
The class AList is based on the
python build-in list class. The
− self. init (..): constructor
Add method adds an object with a
+ self.add(..): Add by index given index value.
+ self.list(..): print instance’s data

Figure 3.10: UML-Diagram for a Array-List Class

Listing 3.8: Implementation of an AList-Class

1 __author__ = ’baeck’
2

3 ’’’
4 extends the python’s buildin class List
5 to get a perfect array feeling
6 ’’’
7

8 from Base import Base


9

10 class AList(Base,list):
11

12 # constructor
13 def __init__(self):
14 Base.__init__(self)
15

16 # add an instance like an array would do


17 # no : index
18 # ojb: object
19 def add(self,no,obj):
20 # check the length
21 ubound = len(self) -1
22

23 if no > ubound:
24 for i in range(ubound+1,no+1):
25 self += [None,]
26

27 # store it!
28 self[no] = obj
29

30 # print the list’s content


31 def list(self):
32 lobj = 0 # counter
33

34 # iterate the container


35 for obj in self:
36

E. Baeck
3.2. PROFILES, THIN WALLED APPROACH Page 81

37 try:
38 obj.list()
39 except:
40 self.appendLog("object %d is unprintable" % lobj)
41 # pass
42

43 lobj += 1

In line 6 we can see, that the AList has two base classes Base and list. The features of both classes
are inherited by our new one. Base is used to print and list is used to store the instance pointers.

In line 15 we see the new method add. If the index is less than the list’s length a general list add is done.
If not, we first enlarge the list up to the needed index value and then call the standard function. If we
do so, the list also can have wholes inside, i.e. None pointers. So we have to be careful with the array
access.

In line 27 we call the list method of every list index. To avoid crashing we simple make the list access
a save access by putting it into a try-except environment.

The Profile class can be considered as a container class for the Element instances. The cardinality is
one and greater. One we would have for a flat steel, two for an L profile and three for a U profile. The
UML diagram is given in figure 3.11.

1 1..*

Base Profile Element

Figure 3.11: Profile’s Element Container

3.2.8 Testing the Profile Class

To test the Profile class we implement a simple main program which creates the points of a TWA
based approximation of the unsymmetric L-profile L 100x50x6. The plates of the L have the length 100
and 50 mm. The thickness of the L is 5 mm.

The implementation of the testing environment is given in listing 3.9.

Listing 3.9: Implementation of a Profile-Testing Environment

1 ’’’
2 check the Profile class
3 3
4 | :2
5 :1 |
6 1---2
7 ’’’
8 import Profile
9 reload(Profile)
10

11 from Profile import Profile


12 from Element import Element

8.5.2018
Page 82 Analysis of Structures - SS 15

13 from Node import Node


14

15 print ">> ProfileApp: check the Profile class"


16 p = Profile("L 100x50x6")
17

18 h = 100.
19 w = 50.
20 t = 6.
21

22 # create Noints
23 n1 = Node(1, -w,t/2.)
24 n2 = Node(2,-t/2.,t/2.)
25 n3 = Node(3,-t/2.,h)
26

27 # create elements
28 e1 = Element(1,n1,n2,t)
29 e2 = Element(2,n2,n3,t)
30

31 # add the elements


32 p.addElement(e1)
33 p.addElement(e2)
34

35 # calculate the section values


36 p.getResults()
37

38 # print profile’s data


39 p.list()
40

41 # view the profile and delete it


42 p.view()
43 del p

The application will give us the following output. We see, that the Profile’s list will print the name
and the section values of the total profile. Then we see that the list method is calling the list method
of the points and elements too. If an index instance is not available, the list method of the AList
will give a hint. In this case there is no element with number 0, therefore we get the message, that in this
slot there is no object found. The profile’s area is given in the standard profile table with 8.73 cm2 . The
deviation comes from the neglected filets.

1 >> ProfileApp: check the profile class


2 19.45.04 |Name.................: L 100x50x6
3 19.45.04 | area...............: 8.6400 cmˆ2
4 19.45.04 | center of mass.....: -10.67 35.67 mm
5 19.45.04 | 1st moments.....: 30.82 -9.22 cmˆ3
6 19.45.04 | 2nd moments ucs.: 200.25 25.52 -11.23 cmˆ4
7 19.45.04 | 2nd moments scs.: 90.32 15.68 21.65 cmˆ4
8 19.45.04 | 2nd moments mcs.: 96.14 9.86 cmˆ4
9 19.45.04 | rotation angle..: 15.06 deg, tan(a) = 0.269
10 19.45.04 | element 1, A= 1, B= 2, t= 6.000 L= 47.000 A= 282.000
11 19.45.04 | center............: -26.500 3.000
12 19.45.04 | static moments....: 8.460e+02 -7.473e+03
13 19.45.04 | moments of inertia: 2.538e+03 2.499e+05 -2.242e+04
14 19.45.04 | node 1, y = -50.000, z = 3.000
15 19.45.04 | node 2, y = -3.000, z = 3.000
16 19.45.04 | element 2, A= 2, B= 3, t= 6.000 L= 97.000 A= 582.000

E. Baeck
3.2. PROFILES, THIN WALLED APPROACH Page 83

17 19.45.04 | center............: -3.000 51.500


18 19.45.04 | static moments....: 2.997e+04 -1.746e+03
19 19.45.04 | moments of inertia: 2.000e+06 5.238e+03 -8.992e+04
20 19.45.04 | node 2, y = -3.000, z = 3.000
21 19.45.04 | node 3, y = -3.000, z = 100.000

Figure 3.12 shows the output of the


profile’s view method. First the pic-
ture is created, then a png file is writ-
ten from the picture and at the end
the viewer is started.2

Figure 3.12: pylab - View of the Profile

2
Note, that the viewer of the used version is very sensible for multiple calls. So if you want to restart the program, you
should first close an open viewer instance. If not, the program will hang.

8.5.2018
Page 84 Analysis of Structures - SS 15

3.2.9 The U-Profile Class

Figure 3.13 shows the UML diagram of the UProfile class. The parameters we pass to the classes
constructor are it’s name, the height, the width and the thicknesses of web and flange.

UProfile

+ self. h: height
The class UProfile contents the
+ self. w: with special features of an U-Profile,
+ self. s: web thickness i.e. the geometric parameters.
+ self. t: flange thickness The class will be inherit the Pro-
file class and will have the feature
− self. init (..): constructor to create this profile with an U
+ self.list(..): list profiles values geometry.
+ self.check(): check input values
+ self.create(..): create thin walled model

Figure 3.13: The U-Profile Class

A class hierarchy UML diagram is given in figure 3.14.

Base Profile UProfile

Figure 3.14: The U-Profile Class Hierarchy

The implementation of the class UProfile is given in listing 3.10. The method create creates the
profile’s Node and Element instances. Before the geometry data is created the input parameters of the
U geometry should be checked. To cancel further activities, the simplest solution is to raise an exception
to break the execution.

Listing 3.10: Implementation of an UProfile-Class

1 ’’’
2 Implementaion of a UProfile class
3 ’’’
4 from Profile import Profile
5 from Node import Node
6 from Element import Element
7

8 class UProfile(Profile):
9

10 def __init__(self,name,h,w,s,t):
11

12 Profile.__init__(self,name)
13

14 self._h = h # height
15 self._w = w # width
16 self._s = s # web thickness
17 self._t = t # flansch thickness
18

E. Baeck
3.2. PROFILES, THIN WALLED APPROACH Page 85

19 # check input parameters


20 self.check()
21

22 # create the geomtry data


23 self.create()
24

25 # check the input parameters


26 def check(self):
27 dMin = 1.
28

29 # checking the parameters


30 if self._h < dMin:
31 raise Exception("invalid height h: %e" % self._h)
32 if self._w < dMin:
33 raise Exception("invalid width w: %e" % self._w)
34 if self._s < dMin:
35 raise Exception("invalid thickness s: %e" % self._s)
36 if self._t < dMin:
37 raise Exception("invalid thickness t: %e" % self._t)
38

39 # create the datastructure of an u-profile


40 def create(self):
41

42 hs = (self._h - self._t)/2.
43 ws = self._w - self._s/2.
44

45 # create the nodes


46 n1 = Node(1,0., hs)
47 n2 = Node(2,0.,-hs)
48 n3 = Node(3,ws, hs)
49 n4 = Node(4,ws,-hs)
50

51 # create the elements


52 e1 = Element(1,n1,n2,self._s)
53 e2 = Element(2,n1,n3,self._t)
54 e3 = Element(3,n2,n4,self._t)
55

56 # assign the elements


57 self.addElement(e1)
58 self.addElement(e2)
59 self.addElement(e3)

3.2.10 Testing the UProfile Class

To test the UProfile class we implement a simple main program, which passes the name and the
parameters of a U-geometry to the UProfile constructor. Then the data of the instance is printed. In
our example we calculate the values of an U80.

8.5.2018
Page 86 Analysis of Structures - SS 15

The implementation of the testing environment is given in listing 3.11.

Listing 3.11: Implementation of a UProfile-Testing Environment

1 ’’’
2 check the UProfile class
3 ’’’
4 import UProfile
5 reload(UProfile)
6

7 from UProfile import UProfile


8

9 print ">> UProfileApp: check the profile class"


10 try:
11 # name h w s t
12 p = UProfile("U80",80,45, 6, 8)
13

14 # calculate the section values


15 p.getResults()
16

17 # print profile’s data


18 p.list()
19

20 # view the profile’s system


21 p.view()
22

23 # delete the instance


24 del p
25 except Exception,e:
26 print "*** error:",e
27

28 print ">> UProfileApp: stop"

The following lines show the output of the test application. The exact value of the U profile’s area is
11 cm2 . Note that we have to put the constructor call into a try-except frame to catch the exception.
1 >> UProfileApp: check the profile class
2 19.57.13 |Name.................: U80
3 19.57.13 | area...............: 11.0400 cmˆ2
4 19.57.13 | center of mass.....: 12.78 0.00 mm
5 19.57.13 | 1st moments.....: 0.00 14.11 cmˆ3
6 19.57.13 | 2nd moments ucs.: 105.75 39.51 0.00 cmˆ4
7 19.57.13 | 2nd moments scs.: 105.75 21.47 0.00 cmˆ4
8 19.57.13 | 2nd moments mcs.: 105.75 21.47 cmˆ4
9 19.57.13 | rotation angle..: 0.00 deg, tan(a) = 0.000
10 19.57.13 | element 1, A= 1, B= 2, t= 6.000 L= 72.000 A= 432.000
11 19.57.13 | center............: 0.000 0.000
12 19.57.13 | static moments....: 0.000e+00 0.000e+00
13 19.57.13 | moments of inertia: 1.866e+05 0.000e+00 0.000e+00
14 19.57.13 | node 1, y = 0.000, z = 36.000
15 19.57.13 | node 2, y = 0.000, z = -36.000
16 19.57.13 | element 2, A= 1, B= 3, t= 8.000 L= 42.000 A= 336.000
17 19.57.13 | center............: 21.000 36.000
18 19.57.13 | static moments....: 1.210e+04 7.056e+03
19 19.57.13 | moments of inertia: 4.355e+05 1.976e+05 2.540e+05
20 19.57.13 | node 1, y = 0.000, z = 36.000
21 19.57.13 | node 3, y = 42.000, z = 36.000

E. Baeck
3.2. PROFILES, THIN WALLED APPROACH Page 87

22 19.57.13 | element 3, A= 2, B= 4, t= 8.000 L= 42.000 A= 336.000


23 19.57.13 | center............: 21.000 -36.000
24 19.57.13 | static moments....: -1.210e+04 7.056e+03
25 19.57.13 | moments of inertia: 4.355e+05 1.976e+05 -2.540e+05
26 19.57.13 | node 2, y = 0.000, z = -36.000
27 19.57.13 | node 4, y = 42.000, z = -36.000
28 >> UProfileApp: stop

Figure 5.2 shows the output of the


profile’s view method. First the pic-
ture is created, then a png file is writ-
ten from the picture and at the end
the viewer is started.

Figure 3.15: pylab - View of the Profile

3.2.11 The Profile Package

If we want to develop reusable code, it’s recommended to create a separate file for every class and put
them into a package. A package is a folder with the package’s name and a file called __init__.py.
If the __init__.py file is not found within the folder, the folder is not interpreted as a package and
the software components of the package can not be loaded. So we introduce a folder called Profile.
To initialize a package we have to create a file named __init__.py in this folder. If the package is
loaded, the __init__.py is executed. All our class files we put into this package folder.

Listing 3.12: Initializing the Package

1 # This script is executed only once, if the package is loaded.


2 # So we print a little to show what’s going on
3 print ">> Package ’Profiles’ is loaded"

If we implement a new class within the Profile package, we only have to import the module base, i.e.
the file Base.py. From this module we import the class Base. So we can write the import statement as
follows.3
1 from Base import Base # inherit from the Base

If we want to use a class from a package, we have to import it with the following statement.
1 from <package>.<module> import <class> as <locale name / alias name>

3
Note, that the file names are case sensitive although you may work on Windows plattform.

8.5.2018
Page 88 Analysis of Structures - SS 15

As an example we use the application for testing a U-profile (see listing 3.11). We move the file on folder
up, so that all our used class files are living in the subfolder Profile.4

The implementation of the testing environment using the package Profile is given in listing 3.13.

Listing 3.13: Implementation of a UProfile-Testing Environment using Package Profile

1 ’’’
2 check the UProfile class
3 ’’’
4 import Profile.UProfile # import total module
5 reload(Profile.UProfile) # reload total module
6 # make sure that’s the current
7 from Profile.UProfile import UProfile # import from a package
8 # from here on every thing is the same...
9 print ">> UProfileApp: check the profile class"
10 try:
11 # name h w s t
12 p = UProfile("U80",80,45, 6, 8)
13

14 # print profile’s data


15 p.listData()
16

17 # delete the instance


18 del p
19 except Exception,e:
20 print "*** error:",e
21

22 print ">> UProfileApp: stop"

3.2.12 A Little Profile Database

To implement a simple profile data base for arbitrary profile instances, we can simply use the Python
buildin object dict 5 and extend it by inheritance with a specific list method (see figure 3.16). The list
iterates the dictionary getting the keys of the stored instances. With the given key we get the instance
pointer from the dictionary. Then we can use the mechanism of the polymorphism and call the instances
specific list method. If there is an error occurring, the try/except error handler will do his job and
executes the except branch code. So we can avoid program crashing due to invalid ore missing pointers.

The code of the ProfileDB class is given below.

Listing 3.14: Implementation of a Profile-Database, the ProfDB-Class

1 from Base import Base # the ProfDB class should inherit the Base class
2

3 # The ProfileDB class should store arbitray profile objects in


4 # a dictionary. Therefore we inherit from the buildin dict object
5 class ProfileDB(Base,dict):
6

7 def __init__(self):
8 Base.__init__(self) # call the Base constructor
9

4
Note, if we do so, we also can move the total folder Profile into Pythons folder Lib/site-packages.
5
A dictionary is used to store instance pointers with an arbitrary access key.

E. Baeck
3.2. PROFILES, THIN WALLED APPROACH Page 89

dict
Python’s build-in dictionary class

ProfileDB
The class ProfileDB is based on a
a dictionary. Profile instances are
− self. init (..): constructor
are stored like in a database.
+ self.list(..): print instance’s data

Figure 3.16: UML-Diagram of the Profile Database

10 # the List method calls the List method of it’s items


11 # if there is no item, the case is handled with an exception block
12 def list(self):
13 iobj = 0 # initialize the object counter
14 for name in self: # iterate the keys of the dictionary
15 try: # open the try block
16 self[name].list() # try to list an object
17 except: # if not possible log it to the log file
18 self.appendLog(" Error: No profile key %s found, slot %d" % \
19 (name,iobj))
20 iobj += 1 # increment the counter
21

22 # the View method calls the View method of it’s items with a False Flag.
23 # if there is no item, the case is handled with an exception block
24 def view(self):
25 iobj = 0 # initialize the object counter
26 for name in self: # iterate the keys of the dictionary
27 try: # open the try block
28 self[name].View(False) # try to write the png file
29 except: # if not possible log it to the log file
30 self.appendLog(" Error: No profile key %s found, slot %d" % \
31 (name,iobj))
32 iobj += 1 # increment the counter

To check the database class ProfileDB we write a little script, which first creates a ProfileDB instance.
Then we create a UProfile instance with the values of the U100. This instance is stored in the dictionary
using the key of it’s name U100. Then we create a second UProfile instance with the values of the U140
and store it as well in the dictionary using it’s name U140 as it’s key. After that we simple call the
ProfileDB instance method list. The data of the two profiles are listed on the screen and into the log file.
After the job is done, we print the png files of our profiles. The code of the testing environment is given
below, the resulting png files are shown in figure .

8.5.2018
Page 90 Analysis of Structures - SS 15

Listing 3.15: Implementation of a Testing-Environment for the ProfileDB-Class

1 ’’’
2 This testing example implements a little profile
3 database. Two U-profiles are created and stored in
4 the database. Then the whole content of the database
5 is printed using the AppendLog method of the base class
6 ’’’
7 # package module class
8 from Profile.UProfile import UProfile
9 from Profile.ProfileDB import ProfileDB
10

11

12 # create Profile database


13 db = ProfileDB()
14

15 # create the instance of an U-Profile


16 prof = UProfile("U100",100.,50.,6.0,8.5)
17

18 # and save it into the db


19 db.setDefault("U100",prof)
20

21 # create the instance of an U-Profile


22 prof = UProfile("U140",140.,60.,7.0,10.)
23

24 # and save it into the db


25 db.setDefault("U140",prof)
26

27 # print the content of the db


28 db.list()
29

30 # print png files of the content of the db


31 db.view()

Figure 3.17: Pictures of the Profiles stored in the Database

E. Baeck
Part II

Scripting with Abaqus

91
4

Some Aspects and Introduction

In this chapter we talk about the Abaqus Student Edition Licence 6.10.. A main aspect will be the
development of Python programs, which should automate the creation of FE models and the subsequent
calculation and preprocessing.

4.1 Aspects of the Abaqus GUI

In this chapter we talk about the Abaqus Student Edition Licence 6.10. GUI1 .

Figure 4.1 shows the Abaqus GUI. A very important item is the combo box to select the module. The
selected module loads the specific menu items. The left window shows the Abaqus object tree. The
bottom window contents an output window for the output messages and the command window for the
Python commands.

Figure 4.1: Abaqus-GUI

1
Graphical User Interface is a window driven program which contents all commands in terms of menu items, buttons, boxes
and so on which are commonly called widgets.

93
Page 94 Analysis of Structures - SS 15

4.2 The Abaqus CAE Module

The Abaqus/CAE kernel offers several possibilities to build up an FE model.

• The GUI offers interactive functions to create the FE model.

• The Python command window offers the possibility to execute single Python commands.

• The Scripting interface offers the possibility to run Python scripts.

• The GUI offers the possibility to record interactive actions in a Python script format. So we can
record and replay everything we do within the GUI.

The Python interpreter creates the input for the CAE kernel. The CAE kernel creates the input stream for
the Abaqus FE-Module.2

2
The input file for the Abaqus FE-Module is a simple Text file, the classical input file, which can also be written ’by hand’.

E. Baeck
4.3. A MODELING CHAIN Page 95

4.3 A Modeling Chain

Figure 4.2 shows how to create a Finite Element model in Abaqus/CAE. It Create Database
is not possible to create elements and nodes directly. Element and nodes are
only created by the mesh generator, which works an the geometric objects, Module Sketch
which are created drawing a sketch. Draw a sketch

The only FE model parameter, which are created directly, are the material Module Part
properties and the section values. This properties are created within the Create a part and
module Property. The properties are then assigned to the geometric objects assign the sketch
(lines, areas and volumes).

After having created a sketch the sketch has to be assigned to a part. If no Module Property
part exists, a part hast to be created. The properties (materials and section Create a properties, ma-
data) are assigned to the sketches’ geometric objects. terials and sections, as-
sign them to sketch lines
To create a mesh, an instance is needed, so an instance has to be created.
The part with the sketch are assigned to the instance for later meshing. Module Assembly
Loadcases are modeled in terms of load steps. So a new step has to be cre- Create an instance and
ated as a container for loads and boundary conditions. Loads and bound- assign the part to it
aries are assigned to the geometric objects of the sketch which were as-
signed to a part before. Module Step
Create a step as
To create the mesh, the mesh’s control parameters should be configured and
container for a load case
the element types are to be assigned. Then the instance can be meshed.

After the mesh is created, the complete model can be assigned to a job. To Module Load
calculate the results the job has to be submitted. Create loads and
boundary condi-
tion within the step

Module Mesh
Set Seeds, elements
per length select and
assign element type
mesh the instance

Module Job
Create a Job and submit

Module Postprocessing
Visualization
and Evaluation
Figure 4.2:
Modeling Chain Diagram

8.5.2018
Page 96 Analysis of Structures - SS 15

4.4 A little interactive Warm Up Example

In section 4.3 we have discussed the Abaqus modeling chain. Fol-


lowing this outlines the subsequent example based on [5] shows how
to create and calculate a simple 3 truss system with a concentrated
force. We use the following parameters.

• Lx horizontal length 1000 mm Ly

• Ly vertical length 1500 mm

• Fx horizontal force -100 kN

• Fy vertical force -100 kN Fx


y
x Fy

Lx
4.4.1 Create a Database Figure 4.3: 3 Trusses

Create Model Database


File/Set Working Directory (setup the desired work folder if necessary)

4.4.2 Create a Sketch

Module: Sketch
Sketch => Create => Name: ’Truss-Example’ => Continue
Add=> Point
=> enter coordinates (0,0), (1000,0), (1000,1500), (0,1500)
Add => Line => Connected Line
=> select (0,0) node with mouse, then (1000,0) node,
right click => Cancel
Add => Line
=> Connected Line
=> select (0,0) node with mouse, then (1000,1500) node,
right click => Cancel
Add => Line
=> Connected Line
=> select (0,0) node with mouse, then (0,1500) node,
right click => Cancel
=> Done

4.4.3 Create a Part

Module: Part
Part => Create => Name: ’Part-1’,=> select 2D Planar, Deformable, Wire
=> Continue
Add => Sketch => select ’Truss-Example’ => Done => Done

E. Baeck
4.4. A LITTLE INTERACTIVE WARM UP EXAMPLE Page 97

4.4.4 Create and Assign Properties

Module: Property
Material => Create => Name: ’Steel’, Mechanical, Elasticity, Elastic
=> set Young’s modulus = 210000, Poisson’s ratio = 0.3 => OK

Section => Create => Name: ’Truss-Section’, Beam, Truss => Continue
=> set Material: ’Material-1’,
Cross-sectional area: 2

Assign Section => select all elements by dragging mouse => Done
=> ’Truss-Section’ => OK => Done

4.4.5 Create the Instance, Assign the Part

Module: Assembly
Instance => Create => ’Part-1’ => Independent (mesh on instance) => OK

4.4.6 Create a Load Step

Module: Step
Step => Create => Name: ’Step-1’, Initial, Static, General => Continue
=> accept default settings
=> OK

4.4.7 Create Loads and Boundary Conditions

Module: Load
Load => Create => Name: ’Step-1’, Step: ’Step 1’, Mechanical,
Concentrated Force => Continue => select node at (0,0) => Done
=> set CF1: -10000 set CF2: -10000 => OK

BC => Create => Name: ’BC-1’, Step: ’Step-1’, Mechanical,


Displacement/Rotation => Continue
=> select nodes at (1000,0), (1000,1500) and (0,1500) using SHIFT key
to select multiple nodes => Done => set U1: 0 and U2: 0

4.4.8 Create the Mesh

Module: Mesh
Seed => Edge by Number => select entire truss by dragging mouse
=> Done => Number of elements along edges: 1 => press Enter => Done

Mesh => Element Type => select entire truss by dragging mouse => Done
=> Element Library: Standard,
Geometric Order: Linear: Family: Truss => OK => Done

Mesh => Instance => OK to mesh the part Instance: Yes

8.5.2018
Page 98 Analysis of Structures - SS 15

4.4.9 Create a Job and Submit

Module: Job
Job => Create => Name: Job-1, Model: Model-1 => Continue
=> Job Type: Full analysis, Run Mode: Background,
Submit Time: Immediately => OK

Job => Submit => ’Job-1’

Job => Manager => Results (enters Module: Visualization)

E. Baeck
5

Scripts and Examples

In this chapter we implement to example scripts, to discuss the automation in Abaqus using the Python
script language.

1. 3 Trusses
The first script gives the implementation of the interactive example, a little 3 trusses system with
one concentrated load. The calculation is performed automatically for a linear analysis.

2. U Profile
The second script gives the implementation of the automated model creation of U Profile using the
thin-walled approach (see also section 3.2 and B.1). The calculation is performed automatically
for a linear analysis and a buckling analysis.

5.1 3 Trusses Script

Within this section the implementation of a script is shown, which automates the example of section
4.4. With the change of the parameter’s values, every system can be calculated with the execution of the
script.

Creating the calculation model we follow our outlines discussed in section 4.3. To avoid problems with
existing project files, we first delete an old database, if exist. Then we set the work directory by the use
of Python’s standard chdir function.1

To get the Python code for the necessary steps, we can simple run the macro recorder and record the
interactive actions. If you do this, then it’s recommended to save the macro file into the work directory
and not into the home directory. The recorded macros are saved into the file abaqusMacros.py.
Note, that the work directory will be set, if the script is executed.

Within the script code the following steps are numbered in the same way.

(1) Create a model


The model is member of the global mdb class. We have to specify the name and the type of the
model. The reference to the created model is saved into the variable myModel for further usage.
1
Note, that on Windows-Systems a path contents backslashes, which in Python are used as escape characters. Therefore if
a backslash is used, we have to duplicate it.

99
Page 100 Analysis of Structures - SS 15

(2) Create a sketch


The ConstrainedSketch is member of the model class, so we use the before saved model reference
myModel to create the sketch. Initializing a sketch we have to specify the sketch’s name and the
sketch page’s size. The return reference is saved into the variable mySketch.
Within our sketch we draw the lines with the method Line. This is done within a for loop iterating
the tuple containing the endpoint coordinates of the lines.

(3) Create a part


The part class is a member of the model class. We create the part instance specifying it’s name
and it’s type. In this we select the TWO_D_PLANAR type. The return of the constructor is saved
into the variable myPart. The method BaseWire of myPart is used to assign the sketch. Now
we have the geometry to start with the creation of nodes and elements using the Abaqus mesh
generator.2

(4) Create the elements properties


The material class is a member of the model class. A material instance is created specifying the
materials name. Within a second step we assign material properties using the Elastic method of
the material class. A tuple containing the Young’s module and the Poisson ratio is assigned to the
parameter table.
In a second step we create the truss section instance. The TrussSection class is a member of the
model class. The return is saved into the variable mySection.
Within the third step the section, which is also linked to the material, will be assigned to the line
objects of the part. So we have to create a region containing the line objects - in this case called
edges - to perform the assignment. By default the selection is recorded with the parts member
edges method getSequenceFromMask(mask=(’[#7]’, ), ). This selection method is
fastest version of selection, but it is also the most cryptic one. If you use this mask, you have to
be sure, that the index of the selected elements does not change and you have to know the selected
objects’ index value. The mask value is created assigning the index values as binary digits. So in
general the mask’s value can be calculated with the following equation.
X
mask = 2i , with i = Objectlabel − 1 for all selected objects (5.1)
i∈Selection

In our case the lines 1, 2 and 3 are selected. So we get

#7 = 716 = 7 = 21−1 + 22−1 + 23−1 = 1 + 2 + 4 (5.2)

After having selected the lines the truss section will be assigned by the part’s method
SectionAssignment. We have to specify the region and the name of the section.

(5) Create an instance


To create the instance, which is needed for meshing, we have to select the rootAssembly object,
which is member of the model class. Because the rootAssembly also is needed later, we assign
it’s reference to the variable root. Within the rootAssembly we create the instance object,
specifying it’s name and the part to assign.
2
Note, that within the GUI nodes and elements can only be created by the mesh generator, i.e. not directly. If the mesh is
created, the node’s and element’s properties can be changed by special system edit methods.

E. Baeck
5.1. 3 TRUSSES SCRIPT Page 101

(6) Create loads and boundary conditions


First we should create a StaticStep class, which is a member of the modul class. The StaticStep
class is a container for loads and boundary conditions.
To create a concentrated load, which is a points load, we have to select first some points, which are
called vertices in Abaqus. The vertices container is a member of the instance class. Vertices also
can be selected with the getSequenceFromMask method, if the label number of the points are
known. The class methode regionToolset.region converts a set of vertices into a region.
The class ConcentratedForce is a member of the model class. We have to specify the loads name.
We have to assign the load to a step and a region and have to set up the load values.
To create boundary conditions we select vertices as well and convert them into a region. Then the
DisplacementBC object, a member of the instance class has to be created like the concentrated
forces specifying it’s name and assigning it to a load step.

(7) Create the mesh


The mesh will be created on the geometric data, in this case the lines of the sketch. So we have
to set up the seeds of the lines, the number of elements, which should be created by the mesh
generator. Like in the case of the section assignment we select all lines using the edges container
of the part object. With #7 we set the mask for our 3 lines. To set the numbers of elements,
we apply the method seedEdgeByNumber of the part class passing the selected edges and the
number of elements to create, in this case one.
Within a second step we select the element type to use in our model with the method elemType of
the class mesh. We select from the standard element library the truss element with the code T2D2.
Then the selected element type is assigned to all elements using the method setElementType
of the part class. As parameters we pass a region, which is created with the mask #7 for all edges
and with an tuple of selected element types.
Within an ultimate step we simple call the method generateMesh of the part class.
Now the mesh is created with all it’s properties and with the method setValues of the standard
viewport instance, which is a member of the session class, we can view the mesh passing the
part instance as displayedObject parameter. If no viewport is explicitly created, the standard
viewport is called Viewport: 1.

(8) Create the job and submit


We set up the jobname and create the job using the standard parameter values. In this case the
job is executed immediately after submission. The return value of the creation step is saved into a
variable for later usage. After the creation of the job, the job is submitted with the job classes’ the
method submit. To automate the analysis of the results two features are available.

– synchronous analysis
In this case the script halts for completion of the calculation. This can be obtained by the
usage of the job classes’ method waitForCompletion. The next commands of the script
are executed after the calculation is completed.
– asynchronous analysis
In this case the script does not halt for completion and the next instructions are executed
immediately. To automate the analysis of the results we have to set up a call back function.
This function is executed automatically after the calculation is done.

8.5.2018
Page 102 Analysis of Structures - SS 15

In our script we implement a synchronous analysis.

(9) Analysis of the result values


To start with the analysis we have to open the result database first. This can be done by the
openOdb method of the class visualization passing the name of the result database. The return
value is a reference to the data base instance.
To access the result values first we have to select the desired step. The step instance contains a
frame container. The result values are to obtain from the member class fieldOutputs. In our case
we select the displacements with the output variable name U. The stresses can be selected with
the output variable S. The values container of the fieldOutput instance contains a member
elementLabel, which is set, if an element result data set is available. If a node result data set
is available the nodeLabel member is set. The result values are items of the data array.
After the analysis is done, you should not forget to close the database with the close member
function.

Listing 5.1: Implementation of a the 3-Trusses Example

1 # copy the next line into the abaqus command window and execute
2 # execfile("c:\\CM\\Cm-AoS\\WS1011\Abaqus\\3Trusses.py")
3

4 from abaqus import *


5 from abaqusConstants import *
6 from caeModules import * # this we need for regionToolset
7

8 modelname = ’3Trusses’
9

10 # delete old database if exists


11 try:
12 del mdb.Models[modelname]
13 print "model ’%s’ deleted." % modelname
14 except:
15 print "No model ’%s’ found!" % modelname
16

17

18 import os # os tools
19 os.chdir(r’c:\\cm\\Cm-AoS\\WS1011\\Abaqus’)
20

21

22 # set up parameters
23 dx = 1000. # length in x
24 dy = 1500. # length in z
25 A = 13.5*100. # U100 area
26 Fx = -100000. # horzontal load
27 Fy = -100000. # vertikal load
28 EMod = 210000. # Young’s module
29 nue = 0.3 # Poisson’s ratio
30

31 # (1) create a model


32 myModel = mdb.Model(name=modelname, modelType=STANDARD_EXPLICIT)
33

34 # (2) create a sketch


35 mySketch = myModel.ConstrainedSketch(name=’3Truss-Sketch’,
36 sheetSize=1.1*2*dy)

E. Baeck
5.1. 3 TRUSSES SCRIPT Page 103

37

38 # - create tuple with coordinates


39 xyPoint = ( (0,0), (dx,0), (dx,dy), (0,dy) )
40 # - iterate the tuple and draw lines
41 for i in range(1,len(xyPoint)):
42 mySketch.Line(point1=xyPoint[0], point2=xyPoint[i])
43

44 # (3) create part


45 myPart = myModel.Part(name=’Trusse-Part-1’,
46 dimensionality=TWO_D_PLANAR, type=DEFORMABLE_BODY)
47

48 # - assign the sketch


49 myPart.BaseWire(sketch=mySketch)
50

51 # (4) set up properties


52 # - create material for steel
53 mySteel = myModel.Material(name = ’Steel’)
54 mySteel.Elastic(table=( (EMod,nue), ))
55

56 # - create truss section


57 mySection = myModel.TrussSection(name=’Truss-Section’, area=A,
58 material=’Steel’)
59

60 # - assign the section to all lines


61 alledges = myPart.edges
62 edges = alledges.getSequenceFromMask(mask=(’[#7 ]’, ), )
63 region = regionToolset.Region(edges=edges)
64 myPart.SectionAssignment(region=region, sectionName=’Truss-Section’, offset=0.0,
65 offsetType=MIDDLE_SURFACE, offsetField=’’,
66 thicknessAssignment=FROM_SECTION)
67

68 # (5) create an instance


69 root = myModel.rootAssembly
70 myInst = root.Instance(name=’Trusses-Instance’, part=myPart, dependent=ON)
71

72 # (6) create a load step


73 myModel.StaticStep(name=’First Step’, previous=’Initial’,
74 description=’Static Load Step’)
75

76 # - create loads for the loadstep


77 v1 = myInst.vertices
78 verts1 = v1.getSequenceFromMask(mask=(’[#2 ]’, ), )
79 region = regionToolset.Region(vertices=verts1)
80 myModel.ConcentratedForce(name=’Load-1’,
81 createStepName=’First Step’, region=region, cf1=Fx, cf2=Fy,
82 distributionType=UNIFORM, field=’’, localCsys=None)
83

84 # - create boundary conditions for the loadstep


85 verts1 = v1.getSequenceFromMask(mask=(’[#d ]’, ), )
86 region = regionToolset.Region(vertices=verts1)
87 myModel.DisplacementBC(name=’BC-1’,
88 createStepName=’First Step’, region=region, u1=0.0, u2=0.0, ur3=UNSET,
89 amplitude=UNSET, fixed=OFF, distributionType=UNIFORM, fieldName=’’,
90 localCsys=None)
91

92 # (7) create mesh

8.5.2018
Page 104 Analysis of Structures - SS 15

93 # - number of elments / line


94 e = myPart.edges
95 pickedEdges = e.getSequenceFromMask(mask=(’[#7 ]’, ), )
96 myPart.seedEdgeByNumber(edges=pickedEdges, number=1, constraint=FINER)
97

98 # - set up the element type


99 elemType1 = mesh.ElemType(elemCode=T2D2, elemLibrary=STANDARD)
100 e = myPart.edges
101 edges = e.getSequenceFromMask(mask=(’[#7 ]’, ), )
102 Region=(edges, )
103 myPart.setElementType(regions=Region, elemTypes=(elemType1, ))
104

105 # - create the mesh


106 myPart.generateMesh()
107

108 # - show the mesh


109 session.viewports[’Viewport: 1’].setValues(displayedObject=myPart)
110

111 # (8) create a job and submit it


112 jobname = modelname+’-Job-1’
113 myJob = mdb.Job(name=jobname, model=modelname,
114 description=’Calculation of the 3 Trusses System’, type=ANALYSIS,
115 atTime=None, waitMinutes=0, waitHours=0, queue=None, memory=50,
116 memoryUnits=PERCENTAGE, getMemoryFromAnalysis=True,
117 explicitPrecision=SINGLE, nodalOutputPrecision=SINGLE, echoPrint=OFF,
118 modelPrint=OFF, contactPrint=OFF, historyPrint=OFF, userSubroutine=’’,
119 scratch=’’)
120 myJob.submit(consistencyChecking=OFF)
121

122 # - note: wait for completion, if the result values should be read form DB
123 myJob.waitForCompletion()
124

125

126 # (9) analysis of results


127 # - open the database: odb file
128 myOdb = visualization.openOdb(jobname+’.odb’)
129

130 # - read data from the last frame


131 frame = myOdb.steps[’First Step’].frames[-1]
132

133 # - printing the displacements


134 data = frame.fieldOutputs[’U’]
135 n = len(data.values)
136 print "%d Result records" % n
137 print ’--no ---ux----- ---uy----’
138 for value in data.values:
139 print "%4d %10.5f %10.5f" % (value.nodeLabel,value.data[0],value.data[1])
140

141 # - printing the stresses


142 data = frame.fieldOutputs[’S’]
143 n = len(data.values)
144 print "%d Result records" % n
145 print ’--no --S11-----’
146 for value in data.values:
147 print "%4d %10.5f" % (value.elementLabel,value.data[0])
148

E. Baeck
5.1. 3 TRUSSES SCRIPT Page 105

149 # close the database


150 myOdb.close()

Figure 5.2 shows the system with it’s loads and boundary condition (see figure 4.3 too). All points are
fixed but not lower left. Here we see the applied point loads in down and left direction.

Figure 5.1: Loads and Boundary Conditions

Figure 5.2 shows the magnitude of displacement on the deformed truss structure.

Figure 5.2: Magnitude of Displacement

8.5.2018
Page 106 Analysis of Structures - SS 15

5.2 U-Girder Script

The goal of our next example is, to create a mesh from a 2 dimensional sketch of
an U geometry by extrusion. Figure 5.2 shows an U profile with it’s parameters
[6]. The U profile geometry is used to create a FE model of a single span girder,
shown in figure 5.4. The girder has a length of L and will be loaded with a line
load q. The boundary conditions should be set according to the simple single
girder system.

The model of the U profile is created step by step according to the modeling chain
diagram (figure 4.2). The created mesh is shown in figure 5.9. Figure ?? shows
the load onto the upper flange of the girder. The girder is supported on both ends
at the lower flange’s edges.

Additional point support is needed to avoid longitudinal and transversal move- Figure 5.3: U Profile
ments as well as rigid body rotations. If we would not do this, it would be like
walking on perfect ice. We may glide in both horizontal directions and may rotate around the vertical
axis without any resistivity. So the stiffness matrix of the girder would be singular without the suppres-
sion of this degrees of freedom (dof ). So we have to fix three dof s which will suppress this rigid body
moves on an arbitrary point in the system. After the calculation is done we will see, whether the choice
was ok, if the reaction forces on this fixed dof s are numerically vanishing.

5.2.1 System and Automated Analysis

Figure 5.4 shows the single span girder in terms of a simple beam. The q
load q is distributed constantly on the girder length L. One end of the
girder is supported hinged and the other side is supported with a roller
support. L

Figure 5.4: Single Span


The following steps of analysis should be done automated by the script. Girder

• According to the calculation switches the script automatically should be able to do a linear static
calculation, a buckling analysis or a frequency analysis;

• for a calculation with loads, the script should check automatically the load balancing, i.e. it should
check whether the applied load will be totally seen as reaction forces;

• the script should find all nodes along a given longitudinal system fiber;

• along this fiber the maximal displacement should be evaluated;

• pictures of the relevant results should be created in terms of png-files.

E. Baeck
5.2. U-GIRDER SCRIPT Page 107

5.2.2 Scripting and OOP

As opposite to our first example, the three trusses (section 5.1), in this case we want to apply the strategy
of OOP to our script and want to implement it in terms of classes.

So we introduce the following classes.

• UGirder, the class of our complete model.

• UGirder should have printing features, deriving them from our class Base like in the Python part
(see section 3.2.9).

• All input data should be handled by a class InputData.

• All result data should be handled by a class ResultData.

Thus we get the following class structure (see 5.5). Following the concept, we have discussed in part 1
section 3.2, all classes are derived from the superclass Base, which should provide all common features.

InputData

Base UGirder

ResultData

Figure 5.5: The U-Girder Class Hierarchy

The class UGirder should get methods for every build step of the system. After the calculation is done
we need some additional methods, which are discussed later.

• createSketch, start with a sketch.

• createPart, creates the part we use.

• createMaterials, creates the materials of the system.

• createProperties, creates the properties of the system.

• assignProperties, assign the properties to the girder’s faces.

• createMesh, creates the mesh on the girder’s faces.

• createInstance, creates the instance, which should be analyzed by Abaqus.

• createStep, creates the load step according to the desired analysis mode.

• createBCs, creates the boundary conditions inside the last created load step.

• createLoads, creates the loads inside the last created load step.

8.5.2018
Page 108 Analysis of Structures - SS 15

5.2.3 Class InputData

Figure 5.6 shows the UML class diagram of the InputData class. This class is used to assemble, check
and work up the girder’s parameters.

InputData

+ self.h: profile’s height


+ self.w: profile’s width
+ self.t: profile’s flange thickness
Only the most important
+ self.s: profile’s web thickness attributes are shown in the
+ self.len: girder’s length diagram to get a compact
+ self.load: load to apply on girder’s top face picture. All attributes are
+ ... some attributes more given in the following ta-
ble.
+ self. init (..): constructor
+ self.setHelpers(..): create helper data
+ self.check(..): check the input parameter
+ self.read(..): read parameters from an input file

Figure 5.6: UML-Diagram of the InputData Class

Attribute Dimension Comment


prjName − project’s name
h mm profile’s height
w mm profile’s width
t mm profile’s flange thickness
s mm profile’s web thickness
len m girder’s length
load kN applied load
2
ymod N/mm Young’s module
nue 1 Poisson ratio
3
nue kg/mm mass density (used for frequency analysis)
maxElement 1 maximal allowed element and node number
webSeed 1 element number along the the web edge
flangeSeed 1 element number along the the flange edge
stepType − specifies the calculation type (static, stability, dynamic)

Besides the parameters discussed in the table above, there are some other attributes in the class, which
are used to prepare or initialize the parameter set for the calculation. This attributes are explained inside
the code.

E. Baeck
5.2. U-GIRDER SCRIPT Page 109

The following listing 5.2 shows the implementation of the class InputData.

Listing 5.2: Implementation of U-Girders’ InputData Class

1 # -*- coding: utf-8 -*-


2 __author__ = ’baeck’
3

4 # module content/class
5 from Base import Base
6

7 # input dataset
8 class InputData(Base):
9

10 # contructor method
11 def __init__(self):
12

13 # initialize Base-Data
14 Base.__init__(self)
15

16 # some constants like macros in C


17 self.LINEAR = 0 # linear static calculation
18 self.BUCKLING = 1 # stability analysis
19 self.FREQUENCY = 2 # frequency analysis
20

21 ## dimensions: N, mm, s
22

23 ## >> start user input data --


24 # parameter of U100
25 self.h = 100. # data according to profile tables [mm]
26 self.w = 50.
27 self.t = 8.5
28 self.s = 6.0
29

30 # system parameter
31 self.len = 4.0 # length [m]
32

33 # material parameters
34 self.ymod = 210000. # N/ m m Young’s module
35 self.nue = 0.3 # Poisson ratio
36 self.rho = 7.8e-6 # mass density kg/ m m
37

38 # loads
39 self.load = 10. # load in kN
40

41 # mesh parameter (seeds)


42 self.maxElement = int(1000) # element and node number of the
43 self.webSeed = int(4) # student version are restricted to 1000
44 self.flangeSeed = int(2) # so we have to be carefull
45 self.lengthSeed = self.maxElement/(self.webSeed + self.flangeSeed*2 +1) -1
46

47 # step or calculation control


48 self.stepType = self.LINEAR
49 self.stepNames = ("Linear","Buckling","Frequency")
50

51 # buckling input data


52 self.numBEigen = 6

8.5.2018
Page 110 Analysis of Structures - SS 15

53 self.numBIterX = 100
54 self.numBVectors = self.numBEigen + 10
55

56 # frequency input data


57 self.numFEigen = 6
58 self.numFIterX = 100
59 self.numFVectors = self.numFEigen + 10
60 ## >> close user input data --
61

62 ## project parameters
63 self.prjName = "U-Girder"
64 self.jobName = self.prjName;
65

66 # output control
67 self.bPngFiles = True # flag to control the file export
68

69 # read the inputdata (till now not implemented)


70 self.read()
71

72 # calculate parameter values for the calculation


73 self.setHelpers()
74

75 # check the input data (till now not implemented)


76 self.check()
77

78 # calculate parameter values for the calculation


79 def setHelpers(self):
80

81 self.hs = (self.h - self.t)/2.


82 self.ws = self.w - self.s/2.
83 self.len *= 1000. # length in [mm]
84 self.p = self.load/(self.ws*self.len)*1.e3
85

86 # check the calculations parameter


87 def check(self):
88 #> it’s your job!
89 pass
90

91 # read the calculations parameter from a file


92 def read(self):
93 #> we’ll see, whether we will do it!
94 pass

E. Baeck
5.2. U-GIRDER SCRIPT Page 111

5.2.4 Class ResultData

Figure 5.7 shows the UML class diagram of the ResultData class. This class is used to hold the calculated
result data.

ResultData

+ self.nodePos: node data of stiff fiber


The data containers we use
+ self.nodeRFo: reaction forces
here are dictionaries, which
+ self.nodeDis: node displacements
are using the node’s key as
+ self.sumRFo: sum of reaction forces to check load balancing key value.

+ self. init (..): contructor


+ self.getMaxDisp(..): calculate the maximal fiber displacement

Figure 5.7: UML-Diagram of the ResultData Class

To get the maximal vertical displacement of a very stiff girder fiber to fade out the cross displacement, we
have to select the fiber’s nodes. This node data is stored in the dictionarry nodePos. After the calculation
is done, we can search for the maximal vertical displacement in the subspace of the fiber nodes.

The following listing 5.3 shows the implementation of the class ResultData.

Listing 5.3: Implementation of U-Girders’ ResultData Class

1 # -*- coding: utf-8 -*-


2 __author__ = ’baeck’
3

4 ’’’
5 container for result data
6 ’’’
7 from math import fabs
8 from Base import Base
9

10 class ResultData(Base):
11

12 # constructor
13 def __init__(self):
14 self.nodePos = {} # to store the node coordinates and it’s label
15 self.nodeRFo = {} # to store the reaction forces
16 self.nodeDis = {} # to store the node displacements
17 self.sumRFo = [0.,0.,0.] # sum vector of the reaction forces
18

19 # calculate the maximum displacement along the center line


20 def getMaxDisp(self):
21 max = 0.
22 for label in self.nodePos:
23 disp = self.nodeDis[label]
24 if fabs(disp[1]) > max: max = fabs(disp[1])
25 return max

8.5.2018
Page 112 Analysis of Structures - SS 15

5.2.5 Class Base

From figure 5.5 we can see, that like in the case of the TWA (see section 3.2 too) all classes in our script
are derived from a superclass, which is called Base.

The only change we make is, to replace the log files name with UGirder.log. The classes’ implementation
is given in listing 5.4.

Listing 5.4: Implementation of U-Girders’ Base Class

1 # -*- coding: utf-8 -*-


2 __author__ = ’baeck’
3

4 ’’’
5 all common functions and variables
6 ’’’
7 # module item our name of this item
8 from datetime import datetime as time
9 import os
10

11 class Base():
12

13 __count = 0 # count the instances


14 __log = "UGirder.log"
15

16 # constructor
17 def __init__(self,log = ""):
18 if log != "": Base.__log = log
19 Base.__count += 1
20 self.appendLog("instance %d created" % Base.__count)
21

22 # destructor
23 def __del__(self):
24 Base.__count -= 1
25

26 # reset all members, here a static method to work on class attributes


27 @staticmethod
28 def resetAll():
29 Base.__count = 0
30 os.remove(Base.__log)
31

32 # print into the log file


33 def appendLog(self,text):
34 t = time.now()
35 timestamp = "%2.2d.%2.2d.%2.2d |" % (t.hour,t.minute,t.second)
36

37 textout = timestamp + text


38 # print into the logfile
39 f = file(Base.__log,"a")
40 f.write(textout + "\n")
41

42 print textout

E. Baeck
5.2. U-GIRDER SCRIPT Page 113

5.2.6 Class UGirder

The UGirder class will be implemented to organize, calculate and analyze the data. The class’ UML
diagram is shown in figure 5.8.

UGirder

+ self.input: InputData object


+ self.result: ResultData object
+ self.model: Abaqus model
+ self.part: Abaqus part
+ self.material: Abaqus material Only the most important
+ self.property: Abaqus property attributes are shown in the
+ self.instance: Abaqus instance diagram to get a compact
picture.
+ self.odb: Abaqus object database
+ self.viewport: Abaqus viewport
+ ... some attributes more

+ self. init (..): constructor


+ self.createSystem(..): create the entire calculation model
+ self.doCalculation(..): starts the solver

Figure 5.8: UML-Diagram of the UGirder Class

The class’ constructor creates an InputData and a ResultData object. To be sure, that all modules are
compiled before execution, i.e. a kind of rebuild, we have to reload this modules. This is only working,
if we load them as entire module (see section A.1 too).

Further methods are implemented to add feature by feature to our U-Girder system. All this steps are
done within the method createSystem.

The fist part of the class’ listing 5.5 shows all methods, to create the geometric system and its mesh. The
mesh we can see in figure 5.9.

Listing 5.5: Implementation of U-Girders’ Main Class UGirder Class, Part System

1 # -*- coding: utf-8 -*-


2 __author__ = ’baeck’
3

4 ’’’
5 the girder’s main class
6 ’’’
7 # for testing only, to be sure, that every modul will be compiled
8 import Base
9 reload(Base)
10 import InputData
11 reload(InputData)
12 import ResultData
13 reload(ResultData)
14

15 # UGirder imports
16 from Base import Base

8.5.2018
Page 114 Analysis of Structures - SS 15

17 from InputData import InputData


18 from ResultData import ResultData
19 from math import sqrt
20

21 # all abaqus imports


22 from abaqus import *
23 from caeModules import *
24 from abaqusConstants import *
25

26 # the UGirder class


27 class UGirder(Base):
28

29 # constructor
30 def __init__(self):
31 Base.__init__(self)
32 Base.resetAll()
33

34 # references to Abaqus objects


35 self.input = InputData()
36 self.result = ResultData()
37 self.model = None
38 self.sketch = None
39 self.part = None
40 self.materials = []
41 self.properties = []
42 self.instance = None
43 self.odb = None
44 self.viewport = None
45 self.selectFlange = None
46 self.selectWeb = None
47

48 # creates all used objects to create the FEM model


49 def createSystem(self):
50 self.createModel()
51 self.createPart()
52 self.createMaterials()
53 self.createProperties()
54 self.assignProperties()
55 self.createMesh()
56 self.getFiberNodes()
57 self.createInstance()
58

59 # creates the model instance


60 def createModel(self):
61 self.appendLog("create model...")
62 try:
63 del mdb.models[self.input.prjName]
64 except:
65 pass
66 self.model = mdb.Model(name=self.input.prjName)
67

68 # creates a part from a sketch


69 def createPart(self):
70 self.appendLog("create a part from a sketch...")
71

72 # do a little abbreviation

E. Baeck
5.2. U-GIRDER SCRIPT Page 115

73 data = self.input
74

75 # create the sketch


76 self.appendLog("create sketch...")
77 sketch = self.model.ConstrainedSketch(name=data.prjName,sheetSize=data.h*2.)
78

79 # specify the polygon points


80 xyPoints = ( (data.ws , data.hs), ( 0., data.hs) ,
81 ( 0.,-data.hs), (data.ws,-data.hs) )
82

83 # create the lines


84 for i in range(1,len(xyPoints)):
85 msg = "Line %d: x1 = %10.3f y1 = %10.3f x2 = %10.3f y2 = %10.3f" % \
86 (i,xyPoints[i-1][0],xyPoints[i-1][1],
87 xyPoints[ i][0],xyPoints[ i][1])
88 self.appendLog(msg)
89 sketch.Line(point1=xyPoints[i-1],point2=xyPoints[i])
90

91 # create the part


92 self.part = self.model.Part(name=data.prjName,
93 dimensionality=THREE_D,
94 type=DEFORMABLE_BODY)
95 self.part.BaseShellExtrude(sketch=sketch,depth=data.len)
96

97 # creates the materials


98 def createMaterials(self):
99 self.appendLog("create materials...")
100 self.materials.append(self.model.Material(name="steel"))
101 self.materials[0].Elastic(table = ( (self.input.ymod, self.input.nue) ,) )
102 self.materials[0].Density(table = ( (self.input.rho, ) ,) )
103

104 # creates the properties


105 def createProperties(self):
106 self.appendLog("create properties...")
107 self.properties = []
108 self.model.HomogeneousShellSection(name="Flange",
109 material="Steel",
110 thickness=self.input.t)
111 self.model.HomogeneousShellSection(name="Web",
112 material="Steel",
113 thickness=self.input.s)
114

115 # assign the properties


116 def assignProperties(self):
117 self.appendLog("assign properties...")
118 data = self.input
119 self.selectFlange = self.part.faces.findAt(
120 ( (data.ws/2., -data.hs,data.len/2.) ,),
121 ( (data.ws/2., data.hs,data.len/2.) ,))
122 #usage of regionToolset:
123 #region = regionToolset.Region(faces = selectFlanges)
124 #myPart.SectionAssignment(region=region, ...)
125 self.part.SectionAssignment(region=(self.selectFlange,),sectionName="Flange")
126

127 # - Web
128 self.selectWeb = self.part.faces.findAt( ( ( 0., 0., data.len/2.) ,),)

8.5.2018
Page 116 Analysis of Structures - SS 15

129 self.part.SectionAssignment(region=(self.selectWeb,),sectionName="Web")
130

131 # creates the mesh


132 def createMesh(self):
133 self.appendLog("generate mesh...")
134 data = self.input
135 # - assign element type: S4R
136 elemType = mesh.ElemType(elemCode = S4R)
137 self.part.setElementType(regions=(self.selectFlange,self.selectWeb),
138 elemTypes = (elemType,))
139

140 # - assign seeds


141 # o flange
142 select = self.part.edges.findAt( ( (data.ws/2., data.hs, 0.), ),
143 ( (data.ws/2.,-data.hs, 0.), ),
144 ( (data.ws/2., data.hs, data.len), ),
145 ( (data.ws/2.,-data.hs, data.len), ),)
146 self.part.seedEdgeByNumber(edges=select,number=data.flangeSeed)
147

148 # o web
149 select = self.part.edges.findAt( ( (0.,0., 0.), ),
150 ( (0.,0., data.len), ),)
151 self.part.seedEdgeByNumber(edges=select,number=data.webSeed)
152

153 # o length direction


154 select = self.part.edges.findAt( ( (data.ws, data.hs, data.len/2.), ),
155 ( ( 0., data.hs, data.len/2.), ),
156 ( ( 0.,-data.hs, data.len/2.), ),
157 ( (data.ws,-data.hs, data.len/2.), ),)
158 self.part.seedEdgeByNumber(edges=select,number=data.lengthSeed)
159

160 # generate mesh


161 self.part.generateMesh()
162

163 # searching for fiber nodes, i.e nodes on the center line
164 def getFiberNodes(self):
165 self.appendLog("find nodes on center fiber...")
166

167 # iterate the container (list: the data is given)


168 for node in self.part.nodes:
169

170 # calculate the distance of the node from the centerline


171 # precision = 1 mm
172 if (sqrt(node.coordinates[0]**2 + node.coordinates[1]**2) < 1.):
173 self.result.nodePos[node.label] = node.coordinates
174

175 self.appendLog("%d elements created." % len(self.part.elements))


176 self.appendLog("%d nodes created." % len(self.part.nodes))
177 self.appendLog("%d nodes on the center line." % len(self.result.nodePos))
178 # print node coordinates on center line
179 # iterate the container (dictionary: -> the key is given)
180 self.appendLog("--no ---------x ---------y ---------z")
181 for label in self.result.nodePos:
182 node = self.result.nodePos[label]
183 self.appendLog("%4d %10.2f %10.2f %10.2f" % \
184 (label,node[0],node[1],node[2]))

E. Baeck
5.2. U-GIRDER SCRIPT Page 117

185

186 # create instance


187 def createInstance(self):
188 self.appendLog("create instance...")
189 self.instance = self.model.rootAssembly.Instance(name=self.input.prjName,
190 part=self.part,
191 dependent=ON)

Figure 5.9: U Girder’s Mesh

To be able to do an independent calculation for the linear static, the stability and the frequency analysis,
we first delete an existing load step called Step-1 and then we create the desired type of load step. If we
do this, we easily can run the calculation of all load steps within one calculation loop.

Listing 5.6: Implementation of U-Girders’ Main Class UGirder Class, Part Loads

2 # create step
3 def createStep(self,type):
4 self.appendLog("create step of type ’%s’..." % self.input.stepNames[type])
5 self.input.stepType = type
6 # first we have to delete an old created step, to clear the momory
7 if len(self.model.steps) > 1: del self.model.steps["Step-1"]
8 # then we create the new one
9 # create a linear static step with it’s data
10 if type == self.input.LINEAR:
11 self.model.StaticStep(name="Step-1",previous="Initial")
12 self.createBCs(type)
13 self.createLoads(type)
14

15 # create a buckling step


16 elif type == self.input.BUCKLING:
17 self.model.BuckleStep(name="Step-1",
18 previous="Initial",
19 numEigen = self.input.numBEigen,
20 maxIterations = self.input.numBIterX,
21 vectors = self.input.numBVectors)
22 self.createBCs(type)
23 self.createLoads(type)

8.5.2018
Page 118 Analysis of Structures - SS 15

24

25 # create a frequency step


26 elif type == self.input.FREQUENCY:
27 self.model.FrequencyStep(name="Step-1",
28 previous="Initial",
29 eigensolver=SUBSPACE,
30 numEigen = self.input.numFEigen,
31 maxIterations = self.input.numFIterX,
32 vectors = self.input.numFVectors)
33 self.createBCs(type)
34

35 # create BC for the U-girder


36 # stepIndex.: step index
37 def createBCs(self,stepIndex):
38 data = self.input
39 self.appendLog("create boudary conditions...")
40 select = self.instance.edges.findAt( ( (data.ws/2.,data.hs, 0.),),
41 ( (data.ws/2.,data.hs,data.len),),)
42 self.model.DisplacementBC(name="vertical line BCs",
43 createStepName="Step-1",
44 region=(select,),
45 u2=0.0)
46

47 select = self.instance.vertices.findAt( ( (0.,data.hs,0.), ),)


48 self.model.DisplacementBC(name="rigid body mode BCs",
49 createStepName="Step-1",
50 region=(select,),
51 u1=0.0,u3=0.0,ur2=0.0)
52

53 # create loads on the top face of the U girder


54 # stepIndex.: step index
55 def createLoads(self,stepIndex):
56 data = self.input
57 self.appendLog("create loads...")
58 select = self.instance.faces.findAt( ( (data.ws/2.,-data.hs, data.len/2.), ),)
59 region = regionToolset.Region(side1Faces=select)
60 self.model.Pressure(name="flange pressure",
61 createStepName="Step-1",
62 region=region,
63 magnitude=data.p)

Figure 5.10 shows the girder with it’s loads and the boundary conditions after the creation of the steps
Linear Static and Buckling.

Listing 5.7: Implementation of U-Girders’ Main Class UGirder Class, Part Job

2 # submit and run the job


3 def runJob(self):
4 self.input.jobName = (self.input.prjName + "-%d") % self.input.stepType
5 self.appendLog("create job %s" % self.input.jobName)
6 job = mdb.Job(name=self.input.jobName,model=self.input.prjName)
7

8 self.input.appendLog("submit job %s" % self.input.jobName)


9 job.submit()
10 job.waitForCompletion()

E. Baeck
5.2. U-GIRDER SCRIPT Page 119

Figure 5.10: Loads and Boundary Conditions

11 self.appendLog("job %s done" % self.input.jobName)


12

13 # open result database und assign it to the viewport


14 def openDatabase(self):
15 self.odbName = self.input.jobName + ".odb"
16 self.appendLog("open database file %s" % self.odbName)
17 self.odb = session.openOdb(self.odbName)
18

19 # set the viewport


20 self.viewport = session.viewports["Viewport: 1"];
21 self.viewport.setValues(displayedObject=self.odb)
22

23 # analyze the result data


24 def analyzeResults(self):
25 # set the font size of the legend
26 self.setFontSize(12)
27 # set the view perspective
28 self.viewport.view.setViewpoint(viewVector=(1, -0.25, -1),
29 cameraUpVector=(0, -1, 0))
30

31 if self.input.stepType == self.input.LINEAR:
32 self.analyzeLinearStep()
33 elif self.input.stepType == self.input.BUCKLING:
34 self.analyzeBuckling()
35 elif self.input.stepType == self.input.FREQUENCY:
36 self.analyzeFrequency()
37

38 # analyze the linear static step


39 def analyzeLinearStep(self):
40 self.appendLog("analyze the linear static results")
41 data = self.input
42 result = self.result
43

44 # calculte the sum of the reaction forces


45 self.result.sumRFo = [0.,0.,0.]
46

8.5.2018
Page 120 Analysis of Structures - SS 15

47 # - select results
48 # |the last frame
49 frame = self.odb.steps["Step-1"].frames[-1]
50

51 # - select the reaction forces


52 rfo = frame.fieldOutputs[’RF’]
53 # - over all nodes
54 for value in rfo.values:
55 # filter nodes with vanishing RFs
56 if (sqrt( value.data[0]**2
57 + value.data[1]**2
58 + value.data[2]**2 ) > 1.e-10):
59 result.nodeRFo[value.nodeLabel] = value.data
60 for i in range(3): result.sumRFo[i] += value.data[i]
61

62 self.appendLog("sum of the reaction forces: %12.3e %12.3e %12.3e" % tuple(result.sumRFo))


63 error = (data.load*1.e3 + result.sumRFo[1])/(data.load*1.e3)*100.
64 self.appendLog("error.....................: %12.3f %%" % error)
65

66 # iterate and print the RF container (dictionary: -> the key is given)
67 self.appendLog("--no ---------RFx ---------RFy ---------RFz")
68 for label in result.nodeRFo:
69 nodeRF = result.nodeRFo[label]
70 self.appendLog("%4d %12.3e %12.3e %12.3e" % \
71 (label,nodeRF[0],nodeRF[1],nodeRF[2]))
72

73 # - select the node displacements


74 dis = frame.fieldOutputs[’U’]
75 # - over all nodes
76 for value in dis.values:
77 result.nodeDis[value.nodeLabel] = value.data
78

79 self.appendLog("maxium center displacement: %12.3e mm" % result.getMaxDisp())


80

81 # optionally create png-Files


82 if data.bPngFiles:
83

84 varList = ("U1","U2","U3")
85 for var in varList:
86 # plot into the viewport
87 self.viewport.odbDisplay.setPrimaryVariable(
88 variableLabel=’U’,
89 outputPosition=NODAL,
90 refinement=(COMPONENT,var))
91

92 # in colour on the system faces


93 self.viewport.odbDisplay.display.setValues(plotState=(CONTOURS_ON_DEF,))
94 self.viewport.view.fitView()
95

96 # print the image into a file


97 pngFile = data.prjName + "-" + data.stepNames[0] + "-" +var
98 self.printPngFile(pngFile)
99

100 # analyze the buckling step


101 def analyzeBuckling(self):
102 self.appendLog("analyze the buckling step")

E. Baeck
5.2. U-GIRDER SCRIPT Page 121

103 data = self.input


104 result = self.result
105

106 # over all eigenforms


107 for i in range(data.numBEigen):
108

109 # plot into the viewport


110 self.viewport.odbDisplay.setPrimaryVariable(
111 variableLabel=’U’,
112 outputPosition=NODAL,
113 refinement=(INVARIANT,’Magnitude’))
114

115 self.viewport.odbDisplay.display.setValues(plotState=(CONTOURS_ON_DEF,))
116 self.viewport.odbDisplay.setFrame(step="Step-1", frame=i+1)
117 self.viewport.view.fitView()
118

119 pngFile = data.prjName + "-" + data.stepNames[1] + ("-E%2.2d" % (i+1,))


120 self.printPngFile(pngFile)
121

122 # analyze the frequency step


123 def analyzeFrequency(self):
124 self.appendLog("analyze the frequency step")
125 data = self.input
126 result = self.result
127

128 # over all eigenforms


129 for i in range(data.numFEigen):
130

131 # plot into the viewport


132 self.viewport.odbDisplay.setPrimaryVariable(
133 variableLabel=’U’,
134 outputPosition=NODAL,
135 refinement=(INVARIANT,’Magnitude’))
136

137 self.viewport.odbDisplay.display.setValues(plotState=(CONTOURS_ON_DEF,))
138 self.viewport.odbDisplay.setFrame(step="Step-1", frame=i+1)
139 self.viewport.view.fitView()
140

141 pngFile = data.prjName + "-" + data.stepNames[2] + ("-E%2.2d" % (i+1,))


142 self.printPngFile(pngFile)
143

144 # set the fontsize


145 # - size....: font size in [pt]
146 def setFontSize(self,size):
147 fsize = int(size*10)
148 self.viewport.viewportAnnotationOptions.setValues(
149 triadFont=’-*-verdana-medium-r-normal-*-*-%d-*-*-p-*-*-*’ % fsize,
150 legendFont=’-*-verdana-medium-r-normal-*-*-%d-*-*-p-*-*-*’ % fsize,
151 titleFont=’-*-verdana-medium-r-normal-*-*-%d-*-*-p-*-*-*’ % fsize,
152 stateFont=’-*-verdana-medium-r-normal-*-*-%d-*-*-p-*-*-*’ % fsize)
153

154 # print the viewports content into a png file


155 # - pngFile...: file name
156 # - myViewport: data
157 def printPngFile(self,pngFile):
158 session.printOptions.setValues(vpBackground=ON)

8.5.2018
Page 122 Analysis of Structures - SS 15

159 session.printToFile(fileName=pngFile, format=PNG,


160 canvasObjects=(self.viewport,))

5.2.7 Run the UGirder Code

If we organize the girder code using classes the main program to run it will be very lightweight (see
listing 5.8). After setting up the work directory, where we will find the created files, we create the mesh
of the system. After this we run a loop over all implemented load steps and run the linear static, the
buckling analysis and the frequency analysis.

After the calculation is done the figures are drawn automatically and stored into png files.

Listing 5.8: Implementation a Main Code for U-Girders to Automate the Calculation

1 __author__ = ’baeck’
2

3 ’’’
4 we can start the script using the followning command:
5 execfile(r’[path]\mainUGirder.py’)
6 execfile(r’c:\unidue\CM\Cm-AoS\AOS-BookOfExamples\Py\Code\Abaqus\UGirder\mainUGirder.py’)
7 ’’’
8

9 # set the workdirectory


10 import os
11 os.chdir(r’c:\unidue\CM\Cm-AoS\AOS-BookOfExamples\Py\Code\Abaqus\UGirder’)
12

13 # for testing only


14 import UGirder
15 reload(UGirder)
16

17 # import UGirder and it’s friends


18 from UGirder import UGirder
19

20 # create the geometric system, the mesh


21 sys = UGirder()
22 sys.createSystem()
23

24 # create steps, run job and analyse


25 for i in range(3):
26 sys.createStep(i)
27 sys.runJob()
28 sys.openDatabase()
29 sys.analyzeResults()

E. Baeck
5.2. U-GIRDER SCRIPT Page 123

5.2.7.1 Results of the Linear Static Step

Figure 5.11 shows the resulting displacements in 1(x), 2(y) and 3(z) direction of a linear analysis.

Figure 5.11: Displacement in 1,2 and 3 Direction of a Linear Analysis

8.5.2018
Page 124 Analysis of Structures - SS 15

5.2.7.2 Results of the Buckling Step

Figure 5.12 shows the buckling modes 1 uto 3.

Figure 5.12: Buckling Modes 1 to 3

E. Baeck
5.2. U-GIRDER SCRIPT Page 125

Figure 5.13 shows the buckling modes 4 uto 6.

Figure 5.13: Buckling Modes 4 to 6

8.5.2018
Page 126 Analysis of Structures - SS 15

5.2.7.3 Results of the Frequency Step

Figure 5.14 shows the dynamic modes 1 uto 3.

Figure 5.14: Dynamic Modes 1 to 3

E. Baeck
5.2. U-GIRDER SCRIPT Page 127

Figure 5.15 shows the dynamic modes 4 uto 6.

Figure 5.15: Dynamic Modes 4 to 6

8.5.2018
Page 128 Analysis of Structures - SS 15

E. Baeck
Part III

Appendix

129
Appendix A

Some Special Problems

In this chapter we talk about some special problems in Python.

A.1 Modules and Packages

If a module is loaded into the Python interpreter to run a script, all changes within the loaded modules
became active, if the script is reloaded. To reload a module on the fly, we have to apply the function
reload(). If a module should be reloaded, we have to import it first without the from key. After the
module is loaded, the module name is declared and we can start the reload() command. After the
reload() we can import the module with the from key.
1 # forced reload for the developer step
2 import InputData # this binds the module to the symbol
3 reload(InputData) # now we reload in any case
4

5 # from InputData import InputData


6 from InputData import InputData # this is our standard import
7 data= InputData()

131
Page 132 Analysis of Structures - SS 15

E. Baeck
Appendix B

Some Theory

B.1 Section Properties

Within this chapter the formulas for the section properties of a thin walled model are given.

A thin walled model for a profile section consists of a set of lines which describes the profile section
geometry at the centerline.

B.1.1 The Area of a Profile Section

The Area is approximately the sum of the areas of the lines of the thin walled model.
Z n
X
A= eµ · dA ≈ eµ,i · Li · ti (B.1)
A i=1

with: Li the length of line i


ti the thickness of line i
eµ,i the relative elasticity of line i (1 for only one material)

B.1.2 First Moments of an Area

The first moments of an area are the area integrals given below. The (y,z) values are related to an given
coordinate system.
Z n
X
Sy = eµ · z · dA ≈ eµ,i · z i · Ai
A i=1
Z Xn
Sz = eµ · y · dA ≈ eµ,i · y i · Ai (B.2)
A i=1

with: Ai the area of a line i


yi the y coordinate of the center of line i
zi the z coordinate of the center of line i

133
Page 134 Analysis of Structures - SS 15

B.1.3 Second Moments of an Area or Moments of Inertia

The moments of inertia can be calculated with the formulas below. If we have a given arbitrary coordinate
system in general we have three values of inertia the Iy , the Iz and the mixed Iyz . If we use the main
coordinate system, the mixed moment of inertia is vanishing, so we use the symbols Iξ and Iη .
Z n
X
2
(zb,i − za,i )2 /12) + z 2i · Ai
 
Iy = eµ · z · dA ≈ eµ,i ·
A i=1
Z n
X
eµ · y 2 · dA ≈ (yb,i − ya,i )2 /12) + y 2i · Ai
 
Iz = eµ,i ·
A i=1
Z Xn
Iyz = eµ · y · z · dA ≈ eµ,i · (((yb,i − ya,i )(zb,i − za,i )/12) + y i · z i ) · Ai ) (B.3)
A i=1

with: Ai the area of a line i


yi the y coordinate of the center of line i
zi the z coordinate of the center of line i
ya,i the y coordinate of the first point of line i
za,i the z coordinate of the first point of line i
yb,i the y coordinate of the second point of line i
zb,i the z coordinate of the second point of line i

To solve an integral like Iy = A z 2 · dA for a polyline we can split up the integral into the sum of
R

integrals over the polyline segments.


Z n Z
X
Iy = z 2 · dA = z 2 · dA (B.4)
A i=1 Ai

To solve an integral for a polyline segment we simple calculate it for the center of mass, because a simple
shift only will give us an additional term, the Steiner term. If we now want to calculate the polyline
integral at the center of mass we rotate the coordinate system by an angle ϕ into the line’s longitudinal
direction, because the transversal dimension, the thickness, is constant and so the respective integral will
be trivial.

E. Baeck
B.1. SECTION PROPERTIES Page 135

Thus we make the following substitution.

(y, z) ⇒ (η, ξ) (B.5)


z = ξ/cos(ϕ) (B.6)

With this substitution we will get the following integral.


η=+t Z ξ=+L/2
ξ2
Z
Iy,i = · dη · dξ
η=−t ξ=−L/2 cos(ϕ)2
Z ξ=+L/2
ξ2
=t· · dξ
cos(ϕ)2
ξ=−L/2
ξ=+L/2
ξ3 1
= t· ·
3 cos(ϕ)2 ξ=−L/2
L3 1
=t· ·
12 cos(ϕ)2
(zb,i − za,i )2
= · Ai with t · L = Ai (B.7)
12

B.1.4 Center of Mass

The coordinates of the center of mass are calculated with the arithmetic mean. Because the numerator of
the arithmetic mean is identical with the first moment of the area (see section B.1.2) and the denominator
is identical with the area of the profile, which is calculated in section B.1.1 we can use this values.
R
y · dA Sz
yc = AR =
dA A
R A
z · dA Sy
zc = AR = (B.8)
A dA A

B.1.5 Moments of Inertia with Respect to the Center of Mass

If we know the center of mass coordinates given in section B.1.4 we can calculate the moments of inertia
with respect to the center of mass using Steiner’s Theorem as follows.

Iy,c = Iy − zc2 · A
Iz,c = Iz − yc2 · A
Iyz,c = Iyz − yc · zc · A (B.9)

8.5.2018
Page 136 Analysis of Structures - SS 15

B.1.6 Main Axis Transformation

To get the moments of inertia Iη and Iξ we have to transform the moments of inertia into the main
coordinate system. Using this coordinate system the mixed moment of inertia is vanishing.

The main axis transformation is given with equation B.10.1

Idel = Iy,c − Iz,c


Isum = Iy,c + Iz,c
q
2 + 4 · I2
Isqr = IDel yz,c
1 −2 · Iyz,c
ϕ= · arctan( )
2 Idel
1
Iη = · (Isum + Isqr )
2
1
Iξ = · (Isum − Isqr ) (B.10)
2

1
The rotation angle ϕ should be shifted into the intervall [−π/2... + π/2]. To avoid a zero division calculating the rotation
angle ϕ a special version of the atan function should be used, which is able to handle the pole problem. In Python like in C this
function is called atan2(x, y), which calculates the atan( xy ).

E. Baeck
Appendix C

Some Python IDEs

C.1 The Aptana - IDE

There are lot of IDEs available for the development of Python software. Most of them are commercial.
One very nice IDE especially for large development projects with a lot of Python files is called Aptana.
Apatana is a special version of the free Eclipse IDE. For this IDE there is a plugin available, which is
called PyDev. To use this IDE first you have to install the basis version of Aptana and then you should
install the plugin and select the desired Python version, which should be installed before. An example
project within the Aptana is shown in figure C.1.

Figure C.1: Aptana IDE

137
Page 138 Analysis of Structures - SS 15

C.2 The PyCharm - IDE

C.2.1 General Statements

PyCharm is an IDE (integrated development environment) which was developed from JetBrains1 . You
can download a free community edition, which we will use in our lecture. The IDE is available for
Windows, Linux and in MacOS.

In contrast to the little PyWin-IDE. PyCharm is working like modern IDEs with projects, i.e. everything
you want to develop, is put into a container, which is called a project. This avoids the sometimes up
coming confusion, if you are working only with single files.

C.2.2 A Hello-Example

If we want to implement the famous Hello World example, known as a general start up, we have to do
this in two steps.

1. We have to create a project within a project directory.

2. We have to create a new Python file, which should print the desired output to the screen.

First of all we have to start the IDE clicking on the icon on the desktop or running the exe-file from the
installation folder. The start up page is display like shown in figure C.2.

Figure C.2: Start up Dialog of PyCharm

After having clicked on ”Create New Prjoject” the dialogs come up, which specifies the project, see
figure C.3. We have set up a new project name. The name is used to specify the project folder. You can
1
You can download the software using the following link https://www.jetbrains.com/pycharm/download/

E. Baeck
C.2. THE PYCHARM - IDE Page 139

edit the default project folder name. In the third control you have to select the desired Python interpreter.
In our case the version 2.7.3 was selected.

Figure C.3: Creating our New Hello Project

After having created the empty Hello project we see the following page, see figure C.4.

Figure C.4: Empty Hello Project

Now we have to create a new Python file, which should print the famous message to the screen. So we
select the menu item File/New... and from the displayed list we select the item file. Then a dialog is
displayed to enter the file’s name. Here we don’t need to input the absolute file name with it’s folder
name. This we see in figure C.5.

Figure C.5: Enter the File’s Name

After having created a new empty file with the name hello.py, we input the one and only statement of our
new application, the statement print "Hello World!". This we see in figure C.6.

To run the application, we have to select the project Hello and click the green run button. If this is done,
a new window if not already opened will be displayed with the console output, i.e. with the message
”Hello World!”. This we can see in figure C.7.

8.5.2018
Page 140 Analysis of Structures - SS 15

Figure C.6: One and Only Statement of Our New Application

Figure C.7: Run the Hello Application

E. Baeck
Appendix D

Conventions

D.1 The Java Code Conventions

The following code convention [7] is published by Oracle (successor of Sun Microsystems, Inc). We
apply this convention to choose names for our software items.

1. Classes
Class names should be nouns, in mixed case with the first letter of each internal word capitalized.
Try to keep your class names simple and descriptive. Use whole words-avoid acronyms and ab-
breviations (unless the abbreviation is much more widely used than the long form, such as URL or
HTML).

2. Methods
Methods should be verbs, in mixed case with the first letter lowercase, with the first letter of each
internal word capitalized.

3. Variables
Except for variables, all instance, class, and class constants are in mixed case with a lowercase first
letter. Internal words start with capital letters. Variable names should not start with underscore _
or dollar sign $ characters, even though both are allowed.
Variable names should be short yet meaningful. The choice of a variable name should be
mnemonic- that is, designed to indicate to the casual observer the intent of its use. One-character
variable names should be avoided except for temporary ”throwaway” variables. Common names
for temporary variables are i, j, k, m, and n for integers; c, d, and e for characters.

4. Constants
The names of variables declared class constants and of ANSI constants should be all uppercase
with words separated by underscores ("_"). (ANSI constants should be avoided, for ease of
debugging.)

141
Page 142 Analysis of Structures - SS 15

E. Baeck
Appendix E

Parallel Computing

E.1 Threads

The most general parallelisation of code is given in the usage of so called threads. A thread is like an
application, which is started and which is running then independent of it’s creating program. Threads
are often used, to run some time consuming events in the background of an interactive program. If
this activity would not run independent in the background, it would block all interactive events of the
application, like clicking on buttons or scrolling the window contents and the user would have the feeling,
that this application is hanging.

Threads run parallel on one processor using a task switch strategy. For example, if we run a browser
and a mailing application on an old computer, we get the feeling, that they are be executed in parallel.
With on processor we can not do this. Applications are executed piecewise sequentially. If the hardware
however comes with more than one processor, in general the operating system, i.e. Windows in our case,
is able to distribute this threads onto all available processor, so that they can be executed in parallel. This
we can see, checking the processor loads.

The disadvantage of this kind of threads is, that in general the end of a thread have to be caught by
the caller, so that the caller is able to use the outcome of the thread. This in general costs an effort of
administration.

E.2 A Multi-Processing Pool

In contrast to general threads we can use a so called Multi-Processing-Pool. This pool is filled this
threads of the same kind. If the calculation is started, all this threads are executed on a given set of
processors. This execution is sequential from the view of the calling program, i.e. the calling program is
calling the Multi-Processing-Pool being executed and will halt until all threads are executed, so that we
will not need a code which is synchronizing the execution of the threads.

A typical use case for this is a simple loop with independent cycles.

A really nice example, which shows the usage of a Multi-Processing-Pool is the calculation of the so
called Mandelbrot set1 . This calculation can be split up in several independent cycles. To show the
1
Benoı̂t B. Mandelbrot, described the Mandelbrot set as a number of complex numbers.

143
Page 144 Analysis of Structures - SS 15

performance of parallel execution we introduce the TimeCheck class given in the listing .

The Mandelbrot set is given by the following iteration formula.


2
zn = zn−1 +c (E.1)

with z, c ∈ C

If the absolute value is less equal two it’s a Mandelbaum set point. Otherwise it’s not. In figure E.1 the
Points of the Mandelbraum set are plotted in the complex number plane.

E.2.1 A Single Processor Solution

The function mandelbrotCalcRow calculates the the data for one row of the Mandelbrot set picture.
We put this function partialCalcRow with its function parameters xrange(h) into a map, which
calculates the values for all function parameters. The function partial is used to reduce the number of
arguments of the function mandelbrotCalcRow simply to one, i.e. the last non set, i.e. the ypos
argument. So the parameter space is reduced from 4 to 1. For this dimension, i.e. ypos, the map is
created. On a i7 processor we need 21 seconds to get the result.

Listing E.1: Mandelbrot Single Processor Solution

1 import matplotlib.pyplot as plt # is used to show the results


2 from functools import partial # to create a one dimensional function
3 from TimeCheck import TimeCheck # performance checker
4

5 # calculation of one mandelbrot row


6 def mandelbrotCalcRow(yPos, h, w, max_iteration = 1000):
7 y0 = yPos * (2/float(h)) - 1 # rescale to -1 to 1
8 row = []
9 for xPos in range(w):
10 x0 = xPos * (3.5/float(w)) - 2.5 # rescale to -2.5 to 1
11 iteration, z = 0, 0 + 0j
12 c = complex(x0, y0)
13 while abs(z) < 2 and iteration < max_iteration:
14 z = z**2 + c
15 iteration += 1
16 row.append(iteration)
17 return row
18

19 # creates a set of calculations


20 def mandelbrotCalcSet(h, w, max_iteration = 1000):
21 partialCalcRow = partial(mandelbrotCalcRow, h=h, w=w,
22 max_iteration = max_iteration)
23 mandelImg = map(partialCalcRow, xrange(h))
24 return mandelImg
25

26 # main program calling the mandelbrot calculations


27 # create the timecheck object
28 s = TimeCheck()
29 # and set current time
30 s.set()
31

32 # run the mandelbrot calculation

E. Baeck
E.2. A MULTI-PROCESSING POOL Page 145

33 mandelImg = mandelbrotCalcSet(400, 400, 1000)


34 # print the performance data
35 s.get("single processor performance")
36

37 plt.imshow(mandelImg)
38 plt.savefig(’mandelimg.png’)
39 # plt.show()

Listing E.2: Output for a i7 Processor

1 21.912 : single processor performance

E.2.2 A Multi Processor Solution

If we now want to use the power of our i7 processor, i.e. if we want to use the 4 available cores, we have
to distribute the calculation load of the Mandelbrot set rows onto this cores. This we see in listing E.3.

Listing E.3: Mandelbrot Multi Processor Solution

1 import multiprocessing # is used to get multi processor support


2 import matplotlib.pyplot as plt # is used to show the results
3 from functools import partial # to create a one dimensional function
4 from TimeCheck import TimeCheck # performance checker
5

6 # calculation of one mandelbrot row


7 def mandelbrotCalcRow(yPos, h, w, max_iteration = 1000):
8 y0 = yPos * (2/float(h)) - 1 # rescale to -1 to 1
9 row = []
10 for xPos in range(w):
11 x0 = xPos * (3.5/float(w)) - 2.5 # rescale to -2.5 to 1
12 iteration, z = 0, 0 + 0j
13 c = complex(x0, y0)
14 while abs(z) < 2 and iteration < max_iteration:
15 z = z**2 + c
16 iteration += 1
17 row.append(iteration)
18 return row
19

20 # creates a set of calculations and distributes it onto 4 processors


21 def mandelbrotCalcSet(h, w, max_iteration = 1000):
22 # make a helper function that better supports pool.map by using
23 # only 1 parameter
24 partialCalcRow = partial(mandelbrotCalcRow, h=h, w=w,
25 max_iteration = max_iteration)
26

27 # creates a pool of process, controls worksers


28 pool =multiprocessing.Pool(processes=4)
29

30 # the pool.map only accepts one iterable, so use the partial function
31 # so that we only need to deal with one paramter.
32 # the pool method map runs the set in parallel
33 mandelImg = pool.map(partialCalcRow, xrange(h))
34 pool.close() # we are not adding any more processes and close
35 pool.join() # tell it to wait until all threads are done before going on
36

8.5.2018
Page 146 Analysis of Structures - SS 15

37 return mandelImg
38

39 # check, if thread is main tread!


40 if __name__==’__main__’:
41

42 # main program calling the mandelbrot calculations


43 # create the timecheck object
44 s = TimeCheck()
45 # and set current time
46 s.set()
47

48 mandelImg = mandelbrotCalcSet(400, 400, 1000)


49 # print the performance data
50 s.get("quadcore performance")
51

52 # show result image


53 plt.imshow(mandelImg)
54 plt.savefig(’mandelimg.png’)

Listing E.4: Output for a i7 Processor

1 9.941 : quadcore performance

We see that the function mandelbrot-


CalcRow in both cases is the same.
One difference is, that in multi proces-
sor case we use the pool and it’s map.
Another difference is, that, if the py-
file is executed, the main run must be
marked, that the main program is not
multiple executed.

We see too, that obvious we only


reach a performance jump of 100%,
i.e. the administration of the load dis-
tribution needs a lot of power. This
comes from the fact, that the python
interpreter has to load the file multi-
ple, which should be executed in par-
allel. If the calculation really splits up
into independent cycles, we would ex- Figure E.1: Mandelbrot Set
pect nearly a factor of 4 instead of 2.

Figure E.1 shows the result of our calculation. Every cycle is calculating one row of this picture.

E. Baeck
Appendix F

Some Special Abaqus-GUI-Features

In this chapter we talk about some special features of the Abaqus-GUI.

F.1 Viewport Annotations

F.1.1 The Legend’s Font Size

Sometimes the standard parameters of the Abaqus GUI are really unlucky. So the standard font is set
to 8 points, i.e. it’s impossible to read the text inside the legend, if we create a standard figure with the
following code. The script will plot the calculated displacements colored onto the displaced system. In
a loop we select the displacement related to all coordinate axis.
1 # - create png-files of the displacement components u1, u2, u3 (x,y,z)
2 varlist = ("U1","U2","U3")
3 for var in varlist:
4

5 # - plot the results into the window


6 myViewport.odbDisplay.setPrimaryVariable( \
7 variableLabel=’U’, outputPosition=NODAL,
8 refinement = (COMPONENT,var))
9 myViewport.view.fitView()
10

11 # - and then into an png-file


12 pngfile = prjname + "-" + var
13 session.printOptions.setValues(vpBackground=ON)
14 session.printToFile(fileName=pngfile, format=PNG,
15 canvasObjects=(myViewport,))

If we record the selection of a proper font we can use this code to set the font size automatically. The
following code snippet will do this (see figure F.2).
1 session.viewports[’Viewport: 1’].viewportAnnotationOptions.setValues(
2 triadFont=’-*-verdana-medium-r-normal-*-*-100-*-*-p-*-*-*’,
3 legendFont=’-*-verdana-medium-r-normal-*-*-100-*-*-p-*-*-*’,
4 titleFont=’-*-verdana-medium-r-normal-*-*-100-*-*-p-*-*-*’,
5 stateFont=’-*-verdana-medium-r-normal-*-*-100-*-*-p-*-*-*’)

147
Page 148 Analysis of Structures - SS 15

The viewport annotations can be changed with Viewport/Viewport Annotation Options...


from the menu.

To change the font size, we select the tab Legend. Within


this tab we see that there are a lot of attributes to specify
the legends layout. One of them is the sub-dialog called
Set Font.... If we click this button, the dialog to set
the fonts will be displayed.

Figure F.1: The Legends attributes

Now we can select the desired font attributes like type or


size. In the last section of this dialog we can assign this
attributes to one or more objects.

Figure F.2: Select and Assign Font Attributes

E. Baeck
F.2. SPECIFY VIEW Page 149

F.2 Specify View

A view can be specified by setting the view direction, called Viewpoint and the Up vector. The Viewpoint
specifies the view direction. We should input a vector of this direction. Only the vector direction is
important not the vector length. The second vector specifies the up direction, so we have to specify this
direction with a vector again, whose direction only is important.

We can input this data within the following dialog of the View menu (see F.3)..

Figure F.3: Specify the View

In following code we can see, that we select from the session’s viewport container the standard view-
port "Viewport: 1". It’s view member provides a method to specify the directions discussed above.
1 session.viewports[’Viewport: 1’].view.setViewpoint(viewVector=(1, -1, 1),
2 cameraUpVector=(0, -1, 0))

8.5.2018
Page 150 Analysis of Structures - SS 15

E. Baeck
Bibliography

[1] H.P. Langtangen:


A Primer on Scientific Programming with Python
Springer-Verlag Berlin Heidelberg, 2009

[2] NumPy Community:


NumPy User Guide
Release 1.4.1, April 2010

[3] SciPy Community:


SciPy Reference Guide
Release 0.8.dev, February 2010

[4] ISO/IEC 19501:2005


Information technology – Open Distributed Processing – Unified Modeling Language
(UML) Version 1.4.2

[5] D. G. Taggart
University of Rhode Island, 2009

[6] O. Lueger
Lexikon der Technik, 1904

[7] Java Code Conventions


Oracle Inc., Sun Microsystems, Inc., September 12, 1997

151
Index

:, 31 area, 133
arithmetic mean, 135
Abaqus as, 17
abaqusMacros, 99
BaseWire, 100 Basic, 24
close, 102 bit’s values, 19
ConstrainedSketch, 100 break, 28
DisplacementBC, 101 bytecode, 5
element type C, 5, 19, 23, 24, 27
T2D2, 101 C#, 5
elemType, 101 Camel Case, 15
fieldOutputs, 102 center of mass, 135
frame, 102 Charles Simonyi, 15
generateMesh, 101 chdir, 99
getSequenceFromMask, 100 class
instance, 100 AList, 75, 79
job, 101 Base, 67
material, 100 Element, 71
mesh, 101 Node, 69
model, 99 Profile, 75
openOdb, 102 ProfileDB, 88, 89
part, 100 UProfile, 75, 84
regionToolset, 101 classes, 55
rootAssembly, 100 code blocks, 25
SectionAssignment, 100 complement, 18
seedEdgeByNumber, 101 ComTypes, 7
session, 101 conditional assignment, 32
setElementType, 101 constructor, 55
StaticStep, 101 continue, 28
step, 102 cos, 17
submit, 101 count, 41
TrussSection, 100
datetime, 47
values, 102
day, 48
vertices, 101
def, 31
viewport, 101
derivative, 36
visualization, 102
destructor, 56
waitForCompletion, 101
dictionary, 42, 88
append, 41
Aptana, 137 e/E format, 23

152
INDEX Page 153

except, 81 MacOS, 138


exception, 84 main axis, 136
extend, 41 Mandelbrot Set, 143
Mandelbrot/Multi Processor Solution, 145
f format, 23
Mandelbrot/Single Processor Solution, 144
factorial, 27
map, 42
factorial(170), 28
mathplotlib, 46
factorial(400), 28
microsecond, 48
file
minute, 48
close, 50
moment of inertia, 134
open, 49
month, 48
read, 50
Monty Python, 5
write, 50
Finite Element Model, 95 name, 24
first moment, 133 negative number, 18
float, 24 Newton, 35
font size, 147 Newton’s Algorithm, 38, 62
for, 27 now, 47
FORTRAN, 5 NumPy, 7
Fortran, 24
OOP, 53, 107
g/G format, 23
global variables, 26 package, 17, 87
Parameters, 31
hour, 48
Performance-Checker, 48, 58
Hungarian Notation, 15
pi, 17
IDE, 137 pop, 41
if, 32 printf, 23
import, 17 private, 55, 56
indent, 25 push, 41
index, 41 PyDev, 137
insert, 41 pylab, 46
int, 24 PythonWin, 12
Interactive window, 13
raise, 84
iteration, 36
random, 45
Java, 5 Random Numbers, 46
Java Code Conventions, 141 readlines, 50
remove, 41
legend, 147 reserved words, 16
Lib, 6 return, 31
Lib/site-packages, 88 reverse, 41
LIFO, 41
Linux, 138 SciPy, 9
list, 39, 40, 50 second, 48
Logging, 52 second moment, 134
long, 24 Setup, 6

8.5.2018
Page 154 Analysis of Structures - SS 15

sin, 17
site-packages, 6
sort, 41
stack, 41
strings, 39
Sun Microsystems, Inc., 15

The Beatles, 42
timedelta, 47
Tkinter, 75
try, 81
tuple, 31, 39
type, 24
type checking, 35

UML, 53
aggregation, 54
class diagram, 53
composition, 54
inheritance diagram, 54
note diagram, 53
note diagram assignment, 53

version, 6
viewport annotations, 148

while, 27
Windows, 138

year, 48

E. Baeck

You might also like