Analysis of Structures

Analysis of Structures
Book of Examples
2015
University of Duisburg-Essen
Faculty of Engineering
Department of Civil Engineering
Static and Dynamic of Shell Structures
Dr. E. Baeck
23.4.2015
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
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
2.4
iii
Analysis of Structures - SS 15
Page iv
3
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.11.1 How to Solve a Quadratic Equation . . . . . . . . . . . . . . . . . . . . . . . .
32
2.11.1.1 A Flow-Chart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
2.11.1.2 The Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
2.12 Function Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
2.12.1 An Abs-Function with Type-Checking . . . . . . . . . . . . . . . . . . . . . . .
35
2.12.2 The Newton-Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
36
2.13 Data Sequences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
40
2.13.1 Working with Tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
40
2.13.2 Working with Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
41
2.13.3 Working with Dictionaries . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
42
2.14 Error Handling with Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
2.14.1 Syntax Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
2.14.2 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
2.14.3 Handling Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
44
2.14.4 Raise Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
45
2.15 Random Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
46
2.16 Date, Time and Timespan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
48
2.17 Working with Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
2.17.1 Open a File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
2.17.2 Write Data into a File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
2.17.3 Close a File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
51
2.17.4 Read Data from a Text File . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
51
2.17.5 A Logger-Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
52
2.18 OOP with Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53
2.18.1 Some UML Diagrams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53
2.18.2 Implementation of Classes in Python . . . . . . . . . . . . . . . . . . . . . . .
55
2.18.2.1 Class Constructor . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
2.18.2.2 Class Destructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
56
2.18.3 Implementation of a Time Stack Class . . . . . . . . . . . . . . . . . . . . . . .
57
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
3.2.3
Testing the Node Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
70
E. Baeck
CONTENTS
II
4
5
III
Page v
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
Scripting with Abaqus
91
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
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
Appendix
A Some Special Problems
129
131
A.1 Modules and Packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
23.4.2015
Analysis of Structures - SS 15
Page vi
B Some Theory
B.1 Section Properties . . . . . . . . . . . . . . . . . . . . . . . .
B.1.1 The Area of a Profile Section . . . . . . . . . . . . . .
B.1.2 First Moments of an Area . . . . . . . . . . . . . . .
B.1.3 Second Moments of an Area . . . . . . . . . . . . . .
B.1.4 Center of Mass . . . . . . . . . . . . . . . . . . . . .
B.1.5 Moments of Inertia with Respect to the Center of Mass
B.1.6 Main Axis Transformation . . . . . . . . . . . . . . .
C Some Python IDEs
C.1 The Aptana - IDE . . . . .
C.2 The PyCharm - IDE . . . .
C.2.1 General Statements
C.2.2 A Hello-Example .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
133
133
133
133
134
135
135
136
.
.
.
.
137
137
138
138
138
D Conventions
141
D.1 The Java Code Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
E Parallel Computing
E.1 Threads . . . . . . . . . . . . . . .
E.2 A Multi-Processing Pool . . . . . .
E.2.1 A Single Processor Solution
E.2.2 A Multi Processor Solution .
.
.
.
.
143
143
143
144
145
F Some Special Abaqus-GUI-Features
F.1 Viewport Annotations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
F.1.1 The Legend’s Font Size . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
F.2 Specify View . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
147
147
147
149
E. Baeck
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
CONTENTS
Page 1
23.4.2015
Page 2
E. Baeck
Analysis of Structures - SS 15
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 Centrum voor Wiskunde en Informatica (CWI) in Amsterdam Netherlands, see figure
1.1
Figure 1.1:
Guido van Rossum
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
the snake.
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 machine is available on a platform, the bytecode can be executed without any adaptions.1 With this advantage of
highly portability Python comes with the general disadvantage of interpreted languages, the disadvantage of a
really bad performance compared to compiled languages
like FORTRAN or C.
1
This is only true, if no platform depended packages like comTypes are used.
5
Figure 1.2: Monty Python
Analysis of Structures - SS 15
Page 6
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 recommended 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
3
The discussed installation was performed on a German system.
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 provides 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 manipulation, 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
23.4.2015
Analysis of Structures - SS 15
Page 8
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
1.2.4
Page 9
Installing the SciPy Package
SciPy [3] is a collection of mathematical algorithms and convenience functions built on the Numpy extension 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 interactive 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.
23.4.2015
Analysis of Structures - SS 15
Page 10
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
7
Notepad++ and PSPad are available on the info.server in /Software/Editors.
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 environment 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 experimental environment to develop new features.
23.4.2015
Analysis of Structures - SS 15
Page 12
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
1.4
Page 13
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
y(t) = v0 · t −
1
· g · t2
2
(1.1)
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
2
3
>>> print 5*0.6 -0.5*9.81*0.6**2
1.2342
>>>
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
2
3
4
5
6
7
>>> v0 = 5
>>> g = 9.81
>>> t = 0.6
>>> y = v0*t - 0.5*g*t**2
>>> print y
1.2342
>>>
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
2
3
4
5
6
# program for computing the height of a ball thrown up in the air
v0 = 5
# initial velocity
g = 9.81
# acceleration of gravity
t = 0.6
# time
y = v0*t - 0.5*g*t**2
# vertical position
print y
# printing the result
23.4.2015
Page 14
E. Baeck
Analysis of Structures - SS 15
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
Analysis of Structures - SS 15
Page 16
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
2
3
>>> import math
>>> math.sqrt(4)
2.0
E. Baeck
2.3. PACKAGES AND MODULES
2.3.2
Page 17
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
2
3
4
5
2.3.3
>>> from math import *
>>> sqrt(4)
2.0
>>> fabs(-2.)
2.0
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
2
3
4
2.3.4
>>> from math import sqrt
>>> sqrt(4)
2.0
>>>
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
2
3
4
5
6
7
8
9
>>> from math import sin as s, cos as c, pi
>>> r = 10
>>> x = r*c(pi/4)
>>> y = r*s(pi/4)
>>> x
7.0710678118654755
>>> y
7.0710678118654746
>>>
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.
23.4.2015
Analysis of Structures - SS 15
Page 18
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.4.2
(2.1)
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
1
**
power operator
x = a**2
%
modulo operator
x = a%2
//
integer division operator x = a//2
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
2.4.3
Page 19
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
ˆ
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
>>>
x = 23 & 13 >>>
5
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
2
3
4
5
6
7
8
2.4.4
# print the value the bits from bit n to bit m
#
n
= 1
m
= 10
bit0 = 1
for i in range(n,m+1):
bit_i = bit0 << i
print "Bit %2d = %6d" % (i,bit_i)
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
2
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
Python’s bit operators are exactly the some as the C bit operators.
23.4.2015
Analysis of Structures - SS 15
Page 20
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
2
3
4
>>> a = 27563
>>> "%X" %a
’6BAB’
>>>
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
2
3
4
5
6
>>> b = 1
>>> b = b<<15
>>> b
32768
>>> "%X" % b
’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 .
The index of the example’s numbers represent the base of the numbering system.
5
A half byte is also called nibble.
4
E. Baeck
2.4. OPERATORS
1
2
3
4
5
6
Page 21
>>> a = 27563
>>> b = a | (1<<15)
>>> b
60331
>>> "%X" % b
’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
2
3
4
5
6
>>> a = 27563
>>> b = a & (˜(1<<7))
>>> b
27435
>>> "%X" % b
’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.6
(2.4)
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
6
Example
<
less than
x = 23 <
<=
less equal
x = 23 <= 23 >>>
True
>
greater
x = 23 >
13 >>>
True
>=
left shift of bits x = 23 >= 23 >>>
True
==
equal
x = 23 == 23 >>>
True
<>
not equal
x = 23 <> 13 >>>
False
!=
non equal
x = 23 != 23 >>>
False
13 >>>
False
There are two non equal operators available. ! = is the C version and <> is the Basic version.
23.4.2015
Analysis of Structures - SS 15
Page 22
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
True
not
logical not x = not (1 < 2)
x = 1 < 2 or
2 > 3 >>>
>>>
False
The following table shows the truth values of the && and the || operator.
Truth tabel of the && operator
2.4.7
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
Membership Operators
With the membership operators you can check whether a value or an object is part of sequence of objects.
Operator Comment
in
is member
Example
x = 2 in (1,2,3)
>>>
not in is not a member x = 2 not in (1,2,3) >>>
2.4.8
True
False
Identity Operators
With the identity operators you can check the identity of two objects.
Operator Comment
is
is identical
Example
x = (1,2) >>> y = x >>> x is y
>>>
is not is not identical x = (1,2) >>> y = x >>> x is not y >>>
7
True
False
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
2.5
Page 23
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
2
3
4
>>> "%d,%3d,%6d" % (2,2,2)
’2, 2,
2’
>>> "%x,%3X,%6X" % (31,31,31)
’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
2
3
4
>>> "%f,%e,%g" % (12.34,12.34,12.34)
’12.340000,1.234000e+01,12.34’
>>> "%.2f,%.2e,%.2g" % (1234567.89,1234567.89,1234567.89)
’1234567.89,1.23e+06,1.2e+06’
23.4.2015
Page 24
2.6
Analysis of Structures - SS 15
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
2
3
4
5
6
7
8
9
10
11
12
13
8
>>> a = 2
>>> b = 3L
>>> c = 4.5
>>> d = 6 + 7j
>>> e = "Hello World"
>>> type (a)
<type ’int’>
>>> type (b)
<type ’long’>
>>> type (c)
<type ’float’>
>>> type(d)
<type ’complex’>
That means without applying provider depended tricks.
E. Baeck
2.7. CODE BLOCKS
14
15
Page 25
>>> type(e)
<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
2
3
4
5
6
if (a
{
c =
d =
...
}
> b)
a + b
a - b
Further Lines of C-Code ...
The following example shows a code block in Fortran77.
1
2
3
4
5
if (a
c =
d =
...
endif
.gt. b) then
a + b
a - b
Further Lines of Fortran-Code ...
Compared with this in Python the code block is bracketed by indent as follows.
1
2
3
4
5
if a > b:
c = a + b
d = a - b
... Further Lines of Python-Code ...
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.
23.4.2015
Analysis of Structures - SS 15
Page 26
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
4
def doSomething(a):
global b
5
print "doSomething...: a = %d, b = %d" % (a,b)
6
7
a = 10 # local variable
b = 20 # global variable
c = 30 # local variable
print "doSomething...: a = %d, b = %d, c = %d" % (a,b,c)
8
9
10
11
12
13
14
15
16
17
18
a = 1
b = 2
c = 3
print "before calling: a = %d, b = %d, c = %d" % (a,b,c)
doSomething(a)
print "after calling.: a = %d, b = %d, c = %d" % (a,b,c)
Listing 2.3: Output from the Testing Example
1
2
3
4
before calling:
doSomething...:
doSomething...:
after calling.:
a
a
a
a
=
=
=
=
1, b = 2, c = 3
1, b = 2
10, b = 20, c = 30
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
2.9
Page 27
Loop for Repetitions
Like all programming languages, which make sense, Python also has some implementations of repetitions, 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! =
n
Y
i
(2.5)
i=1
The implementation of the factorial is given below. Note the importance of the indent, see section 2.7.
1
2
3
4
5
n = 10
p = 1
for i in range(2,n+1):
p *= i
print "%3d! = %10d" % (n,p)
#
#
#
#
#
factorial input
result variable must be initalized by 1
the counter runs from 2 up to n
here we perform the product
write the result into the console
6
7
8
>>>... console window ...
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
2
3
4
5
6
7
n = 10
# factorial input
p = 1
# result variable must be initalized by 1
i = 2
# the counter runs from 2 up to n
while i <=n:
# loop with break condition
p *= i
# perform the product
i += 1
# explicit incrementation
print "%3d! = %10d" % (n,p)
8
9
10
>>>... console window ...
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.
23.4.2015
Page 28
Analysis of Structures - SS 15
The next example shows a nested loop. Very important is the correct code block indent.
1
2
3
for i in range(0,4):
# outer loop
for j in range(0,2):
# inner loop
print "i:%2d, j:%2d" % (i,j) # print counter variables
4
5
6
7
8
9
10
11
12
13
>>>... console window ...
i: 0, j: 0
i: 0, j: 1
i: 1, j: 0
i: 1, j: 1
i: 2, j: 0
i: 2, j: 1
i: 3, j: 0
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
2
3
4
5
6
7
8
>>> for i in range(0,5):
...
if i == 2: continue
...
print "i=%d" % i
...
i=0
i=1
i=3
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
23.4.2015
Analysis of Structures - SS 15
Page 30
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
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 continually 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
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
reached the limit.
2.9.2.2
Exercise
Please implement the algorithm of the Precision-Finder for
the Python float format within a little script like the famous
Hello World example (see section 1.3).
Start
Initializing:
X1 = 1.; X2 = 1.; D = 2.;
Reductionstep:
X2 = X2/D;
Accumulationstep:
S = X1 +X2;
yes
S > X1
no
Resultstep:
Precission = X2 * D;
Stop
Figure 2.3: Flowchart for a Precision Finder
E. Baeck
2.10. FUNCTIONS
2.10
Page 31
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
2
3
def <name> (Parameter list):
Code Block
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
2
3
# function with 2 parameters and 3 returns
def myFunction1(a,b):
return a, b, a**b
4
5
6
7
# function with 2 parameters and 1 return
def myFunction2(a,b):
return a**b
8
9
10
11
# function with 3 parameters and 1 return in a tuple
def myFunction3(a,b):
return (a**b,)
12
13
14
15
ret = myFunction1 (2,3)
print "return of myFunction1... : ", ret
print "length of returned tuple : ", len(ret)
16
17
18
ret = myFunction2 (2,3)
print "return of myFunction2... : ", ret
19
20
21
22
ret = myFunction3 (2,3)
print "return of myFunction3... : ", ret
print "length of returned tuple : ", len(ret)
Runing the code of listing 2.4 will print the following output.
1
2
3
4
5
return
length
return
return
length
of
of
of
of
of
myFunction1...
returned tuple
myFunction2...
myFunction3...
returned tuple
:
:
:
:
:
(2, 3, 8)
3
8
(8,)
1
23.4.2015
Analysis of Structures - SS 15
Page 32
2.11
Branches for Decisions
Decisions are made by the usage of the if statement. The if statement is defined as follows.
1
2
3
4
5
6
if
[boolean expression 1]:
code block 1
elif [boolean expression 2]:
code block 2
elif [boolean expression 3]:
code block 3
7
8
9
10
...
else:
code block else
2.11.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.11. BRANCHES FOR DECISIONS
2.11.1.1
Page 33
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
a=0
yes
no
c=0
no
no
x = − cb
d = b2 − 4 · a · c
d<0
yes
b=0
yes
x1,2 =
Stop
√
−b±i −d
2·a
no solution
yes
infinit
solutions
Stop
Stop
Stop
no
x1,2 =
2.11.1.2
√
−b± d
2·a
Stop
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.
Listing 2.5: Implementation of the Quadratic-Equation-Solver
1
2
3
4
5
6
’’’
solution of a quadratic equation
- handling all special cases ’’’
# import the used functions
from math import fabs as abs, sqrt
23.4.2015
Analysis of Structures - SS 15
Page 34
7
import cmath
8
9
def quadSolve(a,b,c):
10
p = 1.e-15
11
12
# precision of float, is used to
# avoid to test for zero with ==
13
# case: a=0
if abs(a) < p:
14
15
16
# case: b=0
if abs(b) < p:
17
18
19
# case: c=0
if abs(c) < p:
return ("Infinit number of solutions.",)
20
21
22
23
# case: c!=0
else:
return ("No solution possible.",)
24
25
26
27
# case b != 0 (linear case)
else:
x = -c/b
return (x, "Linear case found.")
28
29
30
31
32
# case a != 0 (quadratic case)
else:
d = b**2 -4.*a*c
33
34
35
36
# real case
if d >= 0.:
s = sqrt(d)
x1 = 1./(2.*a)*(-b +s)
x2 = 1./(2.*a)*(-b -s)
return (x1,x2,"Real case of the quadratic problem.")
37
38
39
40
41
42
43
# complex case
else:
s = cmath.sqrt(d)
x1= 1/(2.*a)*(-b +s)
x2= 1/(2.*a)*(-b -s)
return (x1,x2,"Complex case of the quadratic problem.")
44
45
46
47
48
49
50
51
52
53
54
55
#
#
a
b
c
-------- main program ------------------input section
= 1.
= 0.
= 4.
56
57
58
# call of QaudSolve function
result = quadSolve(a,b,c)
59
60
61
62
# check the result tuple, to select the found case
values = len(result)
print "%d values found in return" % values
E. Baeck
2.12. FUNCTION EXAMPLES
Page 35
63
64
65
66
67
# format the found result case
# no or infinit solution(s)
if
values == 1:
print result[0]
68
69
70
71
# linear case
elif values == 2:
print "x = %f, info: %s" % result # (result[0],result[1])
72
73
74
75
76
77
78
79
80
81
# quadratic case
elif values == 3:
if type(result[0]) == complex:
print "x1 = %f+(%fi), x2= %f+(%fi), info: %s" \
% (result[0].real,result[0].imag,
result[1].real,result[1].imag,
result[2])
else:
print "x1 = %f, x2 = %f, info: %s" % result
2.12
Function Examples
In this section we will discuss a new abs function and the Newton algorithm using a function as parameter.
2.12.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
2
# declaring our version of an abs function
def myAbs(x):
3
4
5
6
7
8
9
# process only sensful data types
#
here we use the type class member __name__
#
to check the data type
t = type(x).__name__
if t != ’int’ and t != ’long’ and t != ’float’:
return "Error: Type ’%s’ is not allowed." %t
10
11
12
13
# if data type ok change sign if necessary
if x < 0.: return -x
return x
14
15
16
17
# input section
y = -4
# y = "hello"
# test 1
# test 2
18
23.4.2015
Analysis of Structures - SS 15
Page 36
19
20
# function call
z = myAbs(y)
21
22
23
24
25
26
27
# get return type
t = type(z)
if t == str:
print z
else:
print "Absolute Value of %f = %f" % (y,z)
2.12.2
# second version to check the type
# print error message
# print result
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
interest.
Figure 2.4: Scheme of the Newton Algorithm
The derivative - it’s called fs in the code - is calculated numerical as follows.
f 0 (x) =
df
≈
dx
h
h
f (x + ) − f (x − ) /h
2
2
(2.7)
The Newton scheme can be described as follows.
xi+1 = xi −
f (x)
f 0 (x)
(2.8)
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.
E. Baeck
2.12. FUNCTION EXAMPLES
Page 37
The following flow chart is given for a simple implementation of Newton’s algorithm.
Start
Initializing:
x = x0 ; i = 0;
i ≥ imax
yes
NO ROOT!
Stop
ROOT: x
Stop
NO SLOPE!
Stop
no
F x = f (x)
|F x| ≤ yes
no
F s = f 0 (x)
|F s| ≤ yes
no
x = x−
Fx
Fs
i = i+1
Figure 2.5: Flow Chart for a Simple Newton Implementation
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.
23.4.2015
Analysis of Structures - SS 15
Page 38
Listing 2.7: Implementation of Newton’s-Alogrithm
1
from math import fabs as abs
# import the fabs as abs
2
3
4
5
# implementation of the function of interest
def myF(x):
return x**2 +1.
6
7
8
9
10
11
# calculating the derivative
def fs(f,x,h=1.e-6):
h = float(h)
x = float(x)
return (f(x+0.5*h) - f(x-0.5*h))/h
12
13
14
# implementation of a newton algorithm
def newton(f,x0,e=1.e-10,h=1.e-6,imax=100):
15
16
error = None
# initialize the error code with None
h = float(h)
e = float(e)
x1= float(x0)
# we need some floats
i = 1
while True:
# iteration counter
17
18
19
20
# x to interate
21
22
23
24
f0 = f(x1) # function’s value
if abs(f0) < e:
break
25
26
27
28
# calculating the derivative
f1 = fs(f,x1,h)
if abs(f1) < e:
error = "*** Error: vanishing derivate!"
break
29
30
31
32
33
34
# available iterations exceeded
if i >= imax:
error = "*** Error: no root found!"
break
35
36
37
38
39
# calculating the values for next iteration
x1 -= f0/f1
40
41
42
# increment the iteration counter
i+=1
43
44
45
# return the actual position, the function value
# and the functions slope, the number of performed
# iterations and the error code.
return (x1,f0,f1,i,error)
46
47
48
49
50
51
52
53
54
# the function newton is called with standard parameters
# we pass the function of interest and a supposed start
# position
res = newton(myF,4.)
E. Baeck
2.13. DATA SEQUENCES
Page 39
55
56
57
# the returned tuple is printed into the console window
print res
2.13
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.13.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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
>>> t = ()
# initialize the tuple
>>> t
()
>>> t += (1,)
# append the tuple with a number
>>> t
(1,)
>>> t += (2,3) # append at tuple with a second tuple
>>> t
(1, 2, 3)
>>> t[0]
# calling the tuple’s first element
1
>>> t[2]
# calling the tuple’s third element
3
>>> t[3]
# an error occur, if the index goes out of range
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
IndexError: tuple index out of range
>>> len(t)
# the number of elements is given by the len function
3
Note, that tuples are input data for complex string formatings.
1
2
>>> "x1 = %8.2f, x2 = %8.3f" % (12.3456,12.3456)
’x1 =
12.35, x2 =
12.346’
With the function tuple() a tuple can be created from an iterable object like string or list.
1
2
3
4
5
6
>>> T
>>> T
(1.0,
>>> L
>>> L
[1.0,
=tuple([1.,2.])
2.0)
= list(T)
2.0]
23.4.2015
Analysis of Structures - SS 15
Page 40
7
8
9
>>> T = tuple("Hello World")
>>> T
(’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.13.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.13.1 can be coded like follows.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> L = {]
>>> L
[]
>>> L += [1,]
>>> L
[1,]
>>> L += [2,3]
>>> L
[1, 2, 3]
>>> L[0]
1
>>> L[2]
3
>>> len(L)
3
# initialize the list
# append the list with a number
# append at list with a second list
# calling the lists first element
# calling the list’s third element
# the number of elements is given by the len function
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.
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)
E. Baeck
2.13. DATA SEQUENCES
Page 41
A very important data object or container class which is used especially 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
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 further 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
H remains on the stack
Figure 2.6: Stack Operations
Figure 2.7: Stack Example
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.
2.13.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
2
3
4
5
6
7
8
9
10
11
>>> myDict = {’first item’:1, ’second item’:2}
>>> print myDict[’second item’]
2
>>> beatles = {}
>>> beatles[’drums’] = ’Ringo’
>>> beatles[’bass’] = ’Paul’
>>> beatles[’vocal’] = ’John, Paul, George, Ringo’
>>> beatles[’guitar’] = ’George, John’
>>> print beatles
{’guitar’: ’George, John’, ’vocal’: ’John, Paul, George, Ringo’, ’bass’: ’Paul’,
’drums’: ’Ringo’}
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.
23.4.2015
Analysis of Structures - SS 15
Page 42
2.14
Error Handling with Exceptions
There are (at least) two distinguishable kinds of errors: syntax errors and exceptions.11
2.14.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
2
3
4
5
>>> while True print ’Hello world’
File "<stdin>", line 1, in ?
while True print ’Hello world’
ˆ
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.
2.14.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
2
3
4
5
6
7
8
9
10
11
12
>>> 10 * (1/0)
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ZeroDivisionError: integer division or modulo by zero
>>> 4 + spam*3
Traceback (most recent call last):
File "<stdin>", line 1, in ?
NameError: name ’spam’ is not defined
>>> ’2’ + 2
Traceback (most recent call last):
File "<stdin>", line 1, in ?
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.
11
Parts of this section are taken from the Python 2.7 manual.
E. Baeck
2.14. ERROR HANDLING WITH EXCEPTIONS
Page 43
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.14.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
2
3
4
5
6
7
>>> while True:
...
try:
...
x = int(raw_input("Please enter a number: "))
...
break
...
except ValueError:
...
print "Oops! That was no valid number. Try again..."
...
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.
• 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
2
... except (RuntimeError, TypeError, NameError):
...
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,
s = f.readline()
# read the first line and
i = int(s.strip())
# strip the white spaces
except IOError as e:
# catch the io-errors
print "I/O error(%d): %s" % (e.errno, e.strerror)
except ValueError:
# catch conversion errors
3
4
5
6
7
23.4.2015
Analysis of Structures - SS 15
Page 44
8
9
10
print "Could not convert data to an integer."
except:
# catch the rest
print "Unknown error!"
2.14.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
4
def mySqrt(x):
return math.sqrt(x)
5
6
print mySqrt(-2)
The program crashes with the following output.
1
2
3
4
5
6
7
8
9
10
11
Traceback (most recent call last):
File "C:\Python27\Lib\site-packages\Pythonwin\pywin\framework\scriptutils.py",
line 326, in RunScript
exec codeObject in __main__.__dict__
File "C:\UniDue\CM\Cm-AoS\AOS-BookOfExamples\Py\Code\ExceptionEx01.py", line 7,
in <module>
print Sqrt(-2)
File "C:\UniDue\CM\Cm-AoS\AOS-BookOfExamples\Py\Code\ExceptionEx01.py", line 4,
in mySqrt
return math.sqrt(x)
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
4
5
6
def mySqrt(x):
if x < 0.:
raise Exception("error: negative input value %e!" % x)
return math.sqrt(x)
7
8
try:
9
print mySqrt(-2)
except Exception as e:
print e
10
11
E. Baeck
2.15. RANDOM NUMBERS
Page 45
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.15
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 package, 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.
• 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.
Listing 2.10: Implementation a Kind of Random Walk visualized with two Lists of Random Numbers
1
2
import random
import pylab
# import the random package
# part of matplotlib
3
4
5
6
7
# create random ’count’ numbers in the range [lower:upper]
# a list is returned to the caller
def getRandomNumbers(lower,upper,count):
random.seed()
# initialization of random number generator
23.4.2015
Analysis of Structures - SS 15
Page 46
Figure 2.8: Random, Sorted and Shuffled Walk
8
numbers = []
for i in range(count):
r = lower + (upper-lower)*random.random()
numbers.append(r)
return numbers
9
10
11
12
13
14
15
16
17
18
# main program -----------------------------L = -10.
# lower bound
U = +10.
# upper bound
xN = 100
# number of randoms
19
20
21
22
# random positions
xPos = getRandomNumbers(L,U,xN)
yPos = getRandomNumbers(L,U,xN)
# ...in x-direction
# ...in y-direction
23
24
25
# creating plot of original random values xPos/yPos
pylab.plot(xPos,yPos,"b")
26
27
28
29
# sort the random values
xPos.sort()
yPos.sort()
30
31
32
# creating plot of sorted values xPos/yPos
pylab.plot(xPos,yPos,"r")
33
34
35
36
# create a random order
random.shuffle(xPos)
random.shuffle(yPos)
37
38
39
# creating plot of the shuffeled values xPos/yPos
pylab.plot(xPos,yPos,"g")
40
41
42
# save the plot in a figure using an png-format
pylab.savefig("RandomWalk.png")
43
44
# plot a figure in the matplotlib viewer
E. Baeck
2.16. DATE, TIME AND TIMESPAN
45
Page 47
pylab.show()
46
47
48
49
2.16
# at the end we should close the plot,
# to avoid memory effects
pylab.close()
Date, Time and Timespan
Date and time functions in common are very important and therefor Python supports this with a standard 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
2
3
>>> from datetime import datetime as time
>>> time.now()
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 difference of two datetime objects. The timespan object is called timedelta and is as well an object of the
datetime package.
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
2
3
4
5
6
7
from datetime import datetime as time
t1 = time.now()
... our code snippet ...
t2 = time.now()
t3 = t2 -t1
print t3
>>> 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
2
3
4
5
def getTimeSpanInSeconds(T):
secs = float(T.seconds)
secs += float(T.microseconds)/1.e6
secs += float(t.days)*24.*60.*60.
return secs
23.4.2015
Analysis of Structures - SS 15
Page 48
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
2
# we need the datetime package
from datetime import datetime as time
3
4
5
6
7
8
9
# calculating the timespan in floats
def getTimeSpanInSeconds(T):
t = float(T.seconds)
t+= float(T.microseconds)/1.e6
t+= float(T.days)*24.*60.*60
return t
10
11
12
13
14
nX = 100000
T = ()
L = []
# number of entities to create
# empty tuple
# empty list
15
16
17
18
19
20
# create a tuple with nX items
t1 = time.now()
for i in range(nX):
T += (i,)
t2 = time.now()
21
22
23
sT = getTimeSpanInSeconds(t2-t1) # and calculate the timespan
print "Creation of a tuple with %d items: %.3fs" % (nX,sT)
24
25
26
27
28
29
30
31
# create a list with nX items
t1 = time.now()
for i in range(nX):
L += [i,]
t2 = time.now()
sL = getTimeSpanInSeconds(t2-t1) # and calculate the timespan
print "creation of a list with %d items: %.3fs" % (nX,sL)
32
33
34
35
36
37
38
# convert the list into a tuple
t1 = time.now()
TL = tuple(L)
t2 = time.now()
sTL= getTimeSpanInSeconds(t2-t1) # and calculate the timespan
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
2
3
4
c:\CM\Cm-AoS\WS1011\Python>Timecheck1.py
Creation of a tuple with 100000 items: 33.297s
Creation of a list with 100000 items: 0.063s
Create tuple from list: 0.000s
E. Baeck
2.17. WORKING WITH FILES
2.17
Page 49
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.17.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.
1
2
3
4
5
f = file(<filename>,<access-type>)
...
... example ...
...
f = file("myfile.txt", "w")
2.17.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
2
3
4
5
12
13
#> f.write(<byte-stream>)
#> ...
#> ... example ...
#> ...
f.write("This is my first line\n")
io means input output.
The function fopen is C’s classical function to open a file. The return will be a pointer to a FILE structure.
23.4.2015
Analysis of Structures - SS 15
Page 50
2.17.3
Close a File
After the usage of a file, the file should be closed.
1
2
3
4
5
6
7
#> f.close()
#> ...
#> ... example ...
#> ...
f.open("log.txt","a")
f.write("Write a little log line\n")
f.close()
2.17.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
2
# import the fileinput package
import fileinput
3
4
5
h = -1.
w = -1.
# initialize H value
# initialize W value
file = open("data.in")
lines = file.readlines()
file.close()
print lines
#
#
#
#
for line in lines:
# iterate all lines
6
7
8
9
10
open the file
read entire content
close the file
check the container
11
12
13
14
words = line.split()
# split up into pieces
if len(words) < 1: continue
if words[0] == "#": continue
# ignore blank lines
# ignore comment lines
if words[0] == "H":
h = float(words[1])
# evaluate H key
elif words[0] == "W":
w = float(words[1])
# evaluate H key
15
16
17
18
19
20
21
22
23
24
25
26
print "h = %8.2f" % h
print "w = %8.2f" % w
E. Baeck
# print H value
# print W value
2.17. WORKING WITH FILES
Page 51
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
2
3
4
# this is a comment
# format is key - value like
H 100.
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
2
3
[’# this is a comment\n’, ’# format is key - value like\n’, ’H
10.\n’]
h =
100.00
w =
10.00
2.17.5
100.\n’, ’W
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
2
3
# the filename is passed as a first argument,
# the string to print ist passed as a second
def appendLog(filename,text):
4
5
6
7
t
= time.now()
# get actual time
tstamp = "%2.2d.%2.2d.%2.2d|" % (t.hour,t.minute,t.second)
textout = tstamp + text
# copy the stamp in front of the comment
8
9
10
11
f = file(filename,"a")
f.write(textout + "\n")
f.close()
# open the log file for appending "a"
# write the text into the file with linebreak
# close the log, to save the data on disc
print textout
# write the log to the screen
12
13
23.4.2015
Analysis of Structures - SS 15
Page 52
2.18
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.18.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 architecture 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
rectangular box, which is divided into three sections.
The fist section contents the class’s name. This name
is written centered in bold letters. The second section
contents the attribute’s names of the class and the third
section contents the method’s names.
Class Name
Attributes
Additional information within a simple
Note diagram
Methods
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 information.
MyClass
this is my 1st class
Attribute1
Attribute2
A UML note diagram (see figure 2.10) will be assigned
to an other component of the diagram scene with a simple line.
Method1
Method2
Figure 2.10: A UML Note Diagram Assignment
14
Object orientated Programming is often used with the abbreviation OOP.
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.
15
E. Baeck
2.18. OOP WITH CLASSES
Page 53
Figure 2.11 shows how to draw diagrams for inheriting
classes. An arrow with a white filled arrowhead points
from the inheriting class, the special class, to the inherited class, the base class. The attributes and the methods
of the Base class are now available in the name space of
the inheriting class, i.e. the derived class now has the attributes attributB1, attributB2, attributS1 and
attributS2.
Base Class
Derived Class
− attributeB1
+ attributeS1
− attributeB2
− attributeS2
− methodB1
+ methodS1
+ methodB2
+ methodS2
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
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
instance pointer. Without an instance the item is not available. So an
instance related item can have an arbitrary multiplicity, so every instance
has it’s own item. This item is listed without an underlining.
Base Class
− attributeB1
− attributeB2
− methodB1
+ 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
List A
List B
Method 1
3..* sorted
Class A
1 random
Class B
Figure 2.13 shows a aggregation and a composition. An
aggregation is drawn by a white filled rhombus. An composition is drawn by a black filled rhombus. Aggregation
and compositions describe a container or a list of several
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
within a profile. If a part exists also without a profile, the
parts are described within the profile with an aggregation.
At the ends of the connecting lines the multiplicities are
noted. The multiplicity gives the range of referenced inAttribute A2
Attribute B2
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 Composiour example we have exactly one instance of the class 1.
tion and an Aggregation
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.
Attribute A1
Attribute B1
23.4.2015
Analysis of Structures - SS 15
Page 54
2.18.2
Implementation of Classes in Python
Classes are implemented in Python with the keyword
class. The class key is followed by the name of the
class, which we find in the upper section of the class diagram. If a class inherits from other classes, it’s called subclass. Then the subclass’s name is followed by a comma separated list of classes to inherit from. This classes are called
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.
1
2
3
4
class ClassZ(ClassX, ClassY):
..
class implementation
..
ClassX
ClassY
+ attributeX1
+ attributeY1
− attributeX2
− attributeY2
− methodX1
− methodY1
+ methodX2
+ methodY2
ClassZ
+ attributeZ1
− attributeZ2
+ methodZ1
+ methodZ2
Figure 2.14: Some Classes
2.18.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
def __init__(self,par1,par2):
self.attributeZ1
= par1
self.__attributeZ1 = par2
3
4
5
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.
E. Baeck
2.18. OOP WITH CLASSES
2.18.2.2
Page 55
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
6
def __del__(self):
print "goodby!"
7
8
..
9
10
11
c = ClassZ(1,2)
del c
We should consider, that destructors can not handle exceptions.
23.4.2015
Analysis of Structures - SS 15
Page 56
2.18.3
Implementation of a Time Stack Class
In section 2.16 we have discussed a little program which implements a time checker using a stack container. 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.16. 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
+ self. stack: stack list
+ self. init (..): contructor
+ self.set(..): push a time
The class TimeCheck contents all the data and
functions to use a time stack and to get the
time-span information in a proper float format.
The class is able to present a formated output
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.
E. Baeck
2.18. OOP WITH CLASSES
Page 57
Listing 2.16: Implementation of a Performance-Checker-Class
1
2
3
4
5
6
’’’
Class to investigate the timespan, to measure the performance
by implementing a time stack container
’’’
#
- module
- member
alias
from datetime import datetime as time
# we need the datetime package
7
8
class TimeCheck():
# class name
9
10
11
12
13
# constructor
def __init__(self,log = "timestack.log"):
self._stack = []
# empty list
self._log
= log
# set the logfile’s name
14
15
16
17
# set up the actual time and push it onto the stack
def set(self):
self._stack.append(time.now())
18
19
20
21
22
# calculate the timespan in float
def getTime(self,T):
s = float(T.microseconds)/1.e6 +float(T.seconds) +float(T.days)*24.*60.*60.
return s
23
24
25
# calculate the timespan with a stack object
def get(self,text = ""):
26
27
28
# get the stack length
items = len(self._stack)
29
30
31
32
33
34
# assert(items > 0)
# to assert, that there is a time object
# stored in stack (alternative solution)
if items < 1:
print "*** Error: timestack empty!"
return
35
36
37
38
tStart = self._stack.pop()
# pop the time object from the stack
tEnd
= time.now()
# get the end time
tDel
= self.getTime(tEnd -tStart) # calculate the timedelta in floats
39
40
41
42
43
# we have an maximal indent of 6 columns
indent = 6
space1 = ""
# leading characters for level indent
space2 = ""
# trailed characters to aling the comment
44
45
46
47
# set up indent text
for i in range(items-1):
for i in range(indent -items):
space1 += "."
space2 += " "
# fill in dots
# fill in white spaces
48
49
50
51
# print comment if given
if len(text) > 0:
textout = "%s %8.3f%s: %s" % (space1,tDel,space2,text)
52
53
54
# comment to the screen
print textout
23.4.2015
Analysis of Structures - SS 15
Page 58
55
# logging the comment
f = file(self._log,"a")
f.write(textout + "\n")
f.close()
56
57
58
59
60
return tDel
61
# return the seconds in floats
62
63
64
65
66
67
# application of the TimeCheck class
print ">> Start.."
nX = 50000
T = ()
# empty tuple
L = []
# empty list
68
69
70
# create the timecheck object
s = TimeCheck()
71
72
73
# check the total performance
s.set()
74
75
76
77
78
# check the performance of the tuples
s.set()
for i in range(nX): T+= (i,)
s.get("Creating %d item tuple." % nX)
79
80
81
82
83
# check the performance of the list
s.set()
for i in range(nX): L+= [i]
s.get("Creating %d item list." % nX)
84
85
86
# check the whole performance
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
2
3
4
>> Start..
.
8.282
.
0.016
8.329
E. Baeck
: Creating 50000 item tuple.
: Creating 50000 item list.
: total time
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.
59
Analysis of Structures - SS 15
Page 60
A disadvantage of the first implementation in section 2.12.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;
i ≥ imax
yes
NO ROOT!
Stop
ROOT: x
Stop
no
F x = f (x)
|F x| ≤ yes
no
F s = f 0 (x)
|F s| ≤ yes
x = x+∆
i = i+1
no
x = x−
Fx
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
2
import pylab
from math import fabs as abs
# plot a little (not used in this step)
# import the fabs as abs
3
4
5
6
7
8
# implementation of the function of interest
def myF(x):
return x**2 -1.
# return x**10 -1.
# check the extrem case
# return 0.
# check the constant
9
10
11
12
# calculating the derivative
def fs(f,x,h=1.e-6):
h = float(h)
E. Baeck
3.1. NEWTON, STEP2
13
14
Page 61
x = float(x)
return (f(x+0.5*h) - f(x-0.5*h))/h
15
16
17
# implementation of a newton algorithm
def newton(f,x0,e=1.e-10,h=1.e-6,imax=1000):
18
19
error = None
# initialize the error code with None
h =
e =
x1=
f1=
# we need some floats
20
21
22
23
24
float(h)
float(e)
float(x0)
None
# x to interate
# initialize it for return
25
26
27
28
xL= []
yL= []
sL= []
# list for x-values
# list for the function values for x
# list for the slope values for x
i = 0
while True:
# iteration counter
29
30
31
32
33
34
35
36
# available iterations exceeded
if i >= imax:
error = "*** Error: no root found!"
break
37
38
39
40
41
42
43
44
45
# checking for roots
f0 = f(x1)
#
xL.append(x1)
#
yL.append(f0)
#
if abs(f0) < e:
f1 = fs(f,x1,h)
sL.append(f1)
#
break
function’s value
save x Value
save the functions value
save the last nslope value
46
47
48
49
# calculating the derivative
f1 = fs(f,x1,h)
sL.append(f1)
# save the slope value
50
51
52
53
54
if abs(f1) < e:
x1 += 1.e2*h
i += 1
continue
# little step aside
# avoid dying with a vanishing slope
55
56
57
# calculating the values for next iteration
x1 -= f0/f1
58
59
60
# increment the iteration counter
i+=1
61
62
63
64
65
66
# return the actual position, the function value
# and the functions slope, the number of performed
# iterations and the error code.
# index 0 1 2 3
4 5 6 7
return (x1,f0,f1,i,error,xL,yL,sL)
67
68
# creating a list of function values for a x-list
23.4.2015
Analysis of Structures - SS 15
Page 62
69
70
71
72
73
def getFunctionValues(xL,f):
yL = []
for x in xL:
y = f(x)
yL.append(y)
# yL += [y]
74
return yL
75
76
77
78
79
80
81
82
# create a list of function’ derivative values
def getFunctionDerivateValues(xL,f):
yL = []
for x in xL:
y = fs(f,x)
yL.append(y)
83
return yL
84
85
86
87
88
89
# parameters of the problem
xl = -5.
# lower bound
xu = 5.
# upper bound
xc = 0.5
# increment
90
91
92
93
# visalization of the function and it’s derivative
# create the x-List
xList = pylab.arange(xl,xu,xc)
94
95
96
97
# create list of function’s values
yList = getFunctionValues(xList,Myf)
pylab.plot(xList,yList,’b’)
98
99
100
101
# create list of function’s derivative values
ysList = getFunctionDerivateValues(xList,Myf)
pylab.plot(xList,ysList,’g’)
102
103
104
105
106
107
# the function newton is called with standard parameters
# we pass the function of interest and a supposed start
# position
x0 = 0.
res = newton(Myf,x0)
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# the returned tuple is printed into the console window
print "\n> next run"
print "x0
= %f" % x0
# starting value
print "x
= %f" % res[0]
# last x value
print "f(x) = %f" % res[1]
# last f(x) value
if res[2] is not None:
print "f’(x) = %f" % res[2]
# last f’(x) value
print "i
= %d" % res[3]
# number of iterations
if res[4] is not None:
print "%s" % res[4]
# error message
if len(res[5]) > 0:
print "--------------x -----------f(x) ----------f’(x)"
for i in range(len(res[5])):
print "%15.6e %15.6e %15.6e" % (res[5][i],res[6][i],res[7][i])
print "--- end of code ---\n"
124
E. Baeck
3.1. NEWTON, STEP2
125
126
Page 63
# plot the iteration path
pylab.plot(res[5],res[6],’rp’)
127
128
129
130
# output of plot data
pylab.grid(True)
# show grid lines
pylab.savefig("NewtonStep2.png")
131
132
133
# - show plot data
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
2
3
4
5
6
7
8
9
10
11
12
x0
= 0.000000
x
= 1.000000
f(x) = 0.000000
f’(x) = 2.000000
i
= 18
--------------x -----------f(x) ----------f’(x)
0.000000e+00
-1.000000e+00
0.000000e+00
1.000000e-04
-1.000000e+00
2.000000e-04
5.000000e+03
2.500000e+07
1.000000e+04
2.500001e+03
6.250002e+06
5.000003e+03
1.250001e+03
1.562501e+06
2.500002e+03
6.250008e+02
3.906250e+05
1.250002e+03
23.4.2015
Analysis of Structures - SS 15
Page 64
13
14
15
16
17
18
19
20
21
22
23
24
25
26
3.125012e+02
9.765602e+04
1.562522e+02
2.441375e+04
7.812931e+01
6.103189e+03
3.907105e+01
1.525547e+03
1.954832e+01
3.811370e+02
9.799739e+00
9.503489e+01
4.950891e+00
2.351133e+01
2.576438e+00
5.638031e+00
1.482285e+00
1.197170e+00
1.078460e+00
1.630751e-01
1.002854e+00
5.716204e-03
1.000004e+00
8.122320e-06
1.000000e+00
1.649347e-11
--- end of code ---
6.250025e+02
3.125044e+02
1.562586e+02
7.814211e+01
3.909665e+01
1.959948e+01
9.901783e+00
5.152875e+00
2.964570e+00
2.156919e+00
2.005708e+00
2.000008e+00
2.000000e+00
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
3.2
Page 65
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 created 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.
23.4.2015
Analysis of Structures - SS 15
Page 66
Base
− log: global log file name
− count: global instance counter
The class Base contents common
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
3
4
5
6
7
8
’’’
the Base class of all TWA-classes
’’’
# import some packages
#
|package
#
|
| select the item to import
#
|
|
| alias name
from datetime import datetime as time
9
10
11
12
class Base:
__log
= "profiles.log"
__count = 0
# class attribut, type private
# class attribut, instance counter
13
14
15
16
17
18
19
# construtor
#
|instance pointer
#
|
|optional parameter
def __init__(self,log = ""):
Base.__count += 1
if len(log) > 0: Base.__log = log
# increment the counter
# set a new log-file name
20
21
22
# print the instance counter value
self.appendLog(">> instance %d created!" % Base.__count)
23
24
25
26
27
28
29
30
# print a message into the log file and to the console
#
| instance pointer
#
|
| text to print
def appendLog(self,text):
t
= time.now()
# get the time
tstamp = "%2.2d.%2.2d.%2.2d |" % (t.hour,t.minute,t.second)
textout = tstamp + text
# text to print
31
32
33
34
# use the file object to print with the append mode "a"
f = file(Base.__log,"a")
f.write(textout+"\n")
# write text
35
36
print textout
37
38
39
40
41
E. Baeck
# destructor
def __del__(self):
self.appendLog("instance %d deleted" % Base.__count)
Base.__count -= 1
# decrement the counter
3.2. PROFILES, THIN WALLED APPROACH
3.2.2
Page 67
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
+ x[]: List for point coordinates
The class Node contents the coordinates 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
4
5
# forced reload
import Base
reload(Base)
6
7
8
#
module
item
from Base import Base
9
10
11
# class to describe a profile node
class Node(Base):
12
13
14
15
16
# constructor
#
self pointer
#
number and the coordinates
def __init__(self,no,x,y):
17
18
19
# run the constructor of the Base class
Base.__init__(self)
20
21
try:
22
self._no
= int(no)
self._x
= [float(x),float(y)]
except:
raise "*** error: invalid input!"
23
24
25
26
27
# destructor
23.4.2015
Analysis of Structures - SS 15
Page 68
def __del__(self):
pass
28
29
30
# list the node content
def list(self):
self.appendLog("node %d, x = %10.4f, y = %10.4f" % \
(self._no,self._x[0],self._x[1]))
31
32
33
34
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
3
4
5
’’’
checking the Node class
’’’
import Node
# we have to be sure
reload(Node)
# that we check the current file
6
7
from Node import Node
# import the Node class
n = Node(3,1.,2.)
n.listData()
# we create a point
# and list it’s value
# delete the instance
print n
del n
print n
# let’s print the Nodes address
# and than we delete the instance
# try to print it again
8
9
10
11
12
13
14
15
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
2
3
4
5
6
7
8
9
10
11
12
15.49.12 |>> instance 1 created!
15.49.12 | point
3, y =
1.000, z =
2.000
<Node.Node instance at 0x031AE300>
15.49.12 |instance 1 deleted
Traceback (most recent call last):
File "C:\Python27\Lib\site-packages\Pythonwin\pywin\framework\scriptutils.py",
line 326, in RunScript
exec codeObject in __main__.__dict__
File "C:\UniDue\CM\Cm-AoS\AOS-BookOfExamples\Py\Code\Profiles\NodeApp.py",
line 15, in <module>
print p
# try to print it again
NameError: name ’p’ is not defined
E. Baeck
3.2. PROFILES, THIN WALLED APPROACH
3.2.4
Page 69
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
+ n[]: list of point instance pointers
The class Element contents the
element’s point data.
+ t: line’s thickness
− self. init (..): constructor
+ self.getL(): get line’s length
+ self.getA(): get area
+ self.getS(): get static moments
Node
+ no: node number
+ 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
23.4.2015
Analysis of Structures - SS 15
Page 70
The implementation of the class Element is given in listing 3.5.
Listing 3.5: Implementation of an Element-Class
1
2
3
4
5
6
__author__ = ’baeck’
’’’
implementation of an element class
’’’
import Base
reload(Base)
7
8
9
#
module
item
from Base import Base
10
11
12
#
| inherit the Base class
class Element(Base):
13
14
15
# constructor
def __init__(self,no,node1,node2,t):
16
17
Base.__init__(self)
18
19
20
21
self._no = no
self._n = [node1,node2]
self._t = t
22
23
24
25
26
# calculate projected length x,y
# i: dimension
def delX(self,i):
return self._n[1]._x[i] - self._n[0]._x[i]
27
28
29
30
# calculate the length of the element
def getL(self):
return (self.delX(0)**2 + self.delX(1)**2)**0.5
31
32
33
34
# calculate the element’s area
def getA(self):
return (self.getL()*self._t)
35
36
37
38
39
# calculate the center coordinates of an element
# i: dimension (y,z)
def getC(self,i):
return ( (self._n[1]._x[i] + self._n[0]._x[i])/2. )
40
41
42
43
44
# calculate the static moment of the element
# i: dimension (y,z)
def getS(self,i):
return ( self.getC((i+1)%2)*self.getA())
45
46
47
48
49
50
51
52
E. Baeck
# calculate the moment of inertia
# i: dimension (yy,zz,yz)
def getI(self,i):
if i < 2:
j = (i+1)%2
return ( (self.delX(j)**2/12. + self.getC(j)**2)*self.getA() )
else:
3.2. PROFILES, THIN WALLED APPROACH
Page 71
return ( (self.delX(0)*self.delX(1)/12. + self.getC(0)*self.getC(1))
*self.getA() )
53
54
55
56
57
58
59
60
61
62
63
64
65
3.2.5
# list the elements data
def list(self):
self.appendLog("element %d: nodes: %d %d, t = %.2f, A = %.1f" %
(self._no, self._n[0]._no, self._n[1]._no, self._t,self.getA() ))
self.appendLog("
center..............: %10.3e %10.3e" %
(self.getC(0),self.getC(1)))
self.appendLog("
static moments......: %10.3e %10.3e" %
(self.getS(0),self.getS(1)))
self.appendLog("
moments.of inertia..: %10.3e %10.3e %10.3e" %
(self.getI(0),self.getI(1),self.getI(2)))
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
3
4
5
’’’
check the Element class
’’’
import Element
reload(Element)
# do this if you want to sure
# that the module file is the currend one
from Element import Element
from Node import Node
# of course we need the Element class
# and the Node class too
6
7
8
9
10
11
h = 200.
t = 5.
# thickness
12
13
14
15
# create the points
n1 = Node(3,0.,-h/2.)
n2 = Node(2,0., h/2.)
16
17
18
# create the element
e1 = Element(2,n1,n2,t)
19
20
21
# print the element’s data
e1.list()
22
23
24
25
26
# delete instances
del n1
del n2
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
23.4.2015
Page 72
Analysis of Structures - SS 15
call of the according methods.
1
2
3
4
5
6
7
8
9
10
11
12
>>> 15.57.08 |>> instance 1 created!
15.57.08 |>> instance 2 created!
15.57.08 |>> instance 3 created!
15.57.08 | element
2, A=
3, B=
2, t=
5.000 L= 200.000 A=
15.57.08 | center............:
0.000
0.000
15.57.08 | static moments....: 0.000e+00 0.000e+00
15.57.08 | moments of inertia: 3.333e+06 0.000e+00 0.000e+00
15.57.08 | node
3, y =
0.000, z =
-100.000
15.57.08 | node
2, y =
0.000, z =
100.000
15.57.08 |instance 3 deleted
15.57.08 |instance 2 deleted
15.57.08 |instance 1 deleted
1000.000
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
3.2.6
Page 73
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
+ self.list(..): List profiles values
+ self.addElement(..): insert a new Element
The class Profile contents all
common features of a profile
especially the containers for the
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.
23.4.2015
Analysis of Structures - SS 15
Page 74
UProfile
+ self. h: height
+ self. w: with
+ self. s: web thickness
+ self. t: flange thickness
− self. init (..): constructor
+ self.list(..): list profiles values
The class UProfile contents the
special features of an U-Profile,
i.e. the geometric parameters.
The class will be inherit the Profile class and will have the feature
to create this profile with an U
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
+ self. t: thickness
− self. init (..): constructor
+ self.list(..): list profiles values
The class TubeProfile contents
the special features of a TubeProfile, especially the geometric
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
4
5
6
7
__author__ = ’baeck’
’’’
Profile class to calculate section values
with the thinwalled approximation
’’’
8
9
10
from Base import Base
from AList import AList
11
E. Baeck
3.2. PROFILES, THIN WALLED APPROACH
12
Page 75
class Profile(Base):
13
14
15
# constructor
def __init__(self,name):
16
17
Base.__init__(self)
18
19
20
self._name = name
self._elem = AList()
# profile name
# element container
# result data
self._a
= 0.
self._s
= [0.,0.]
self._e
= [0.,0.]
self._iu
= [0.,0.,0.]
self._ic
= [0.,0.,0.]
self._ip
= [0.,0.]
self._alp = 0.
#
#
#
#
#
#
21
22
23
24
25
26
27
28
29
static moments
center of mass coordinates
moment of intertia in user coordinates
moment of intertia in center of mass coordinates
moment of intertia in principal coordinates
rotation angle
30
31
32
33
# add an element into the profile container
def addElement(self,e):
self._elem.add(e._no,e)
34
35
36
# caculate the sections values of the profile
def getResults(self):
37
38
elements = 0
# element counter
39
40
41
# sum up all element contributions
for e in self._elem:
42
43
44
# only for available elements!
if e is not None:
45
46
47
# area
self._a += e.getA()
48
49
50
51
# static moment
for i in range(2):
# [0],[1]
self._s[i] += e.getS(i)
52
53
54
55
# moment of inertia
for i in range(3):
self._iu[i] += e.getI(i)
56
57
elements += 1
# count the elements
58
59
if elements < 1: raise "error: no elements found!"
60
61
62
63
# calculate the center of mass coordinates
self._e[0] = self._s[1]/self._a
self._e[1] = self._s[0]/self._a
64
65
66
# calculate the princial values
self.getPValues()
67
23.4.2015
Analysis of Structures - SS 15
Page 76
68
return (self._a,self._s,self._ip,self._alp)
69
70
71
72
73
# calculate the principal values
# shift and rotate!
def getPValues(self):
import math
74
75
76
77
78
# shift the
self._ic[0]
self._ic[1]
self._ic[2]
moment of inertia into the center of mass cs
= self._iu[0] - self._e[1]*self._e[1]*self._a
= self._iu[1] - self._e[0]*self._e[0]*self._a
= self._iu[2] - self._e[0]*self._e[1]*self._a
79
80
81
82
83
# introduce some helpers
idel = self._ic[0] - self._ic[1]
isum = self._ic[0] + self._ic[1]
isqr = math.sqrt(idel*idel + 4.*self._ic[2])
84
85
86
87
# calculate the principal values
self._ip[0] = 0.5*(isum + isqr)
self._ip[1] = 0.5*(isum - isqr)
88
89
90
# calculate the rotation angle
self._alp
= 0.5*math.atan2(-2.*self._ic[2],idel)
91
92
93
# get angle value in degrees
self._alp *= 45./math.atan(1.)
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# list the profile’s data
def listData(self):
self.appendLog("name..................: %s" % self._name)
self.appendLog("area..................: %10.2f cmˆ2" % (self._a/1.e2,))
self.appendLog("center of mass .......: %10.2f %10.2f cm" % \
(self._e[0]/1.e1,self._e[1]/1.e1))
self.appendLog("static moments .......: %10.2f %10.2f cmˆ3" % \
(self._s[0]/1.e3,self._s[1]/1.e3))
self.appendLog("moment of inertia
uc: %10.2f %10.2f %10.2f cmˆ4" % \
(self._iu[0]/1.e4,self._iu[1]/1.e4,self._iu[2]/1.e4))
self.appendLog("moment of inertia
cc: %10.2f %10.2f %10.2f cmˆ4" % \
(self._ic[0]/1.e4,self._ic[1]/1.e4,self._ic[2]/1.e4))
self.appendLog("moment of inertia
pc: %10.2f %10.2f cmˆ4" % \
(self._ip[0]/1.e4,self._ip[1]/1.e4))
self.appendLog("rotation angle
: %10.2f " % self._alp)
110
111
112
# print a picture of the profile geometry
def view(self,viewer = True):
113
114
try:
115
import pylab
except:
self.appendLog("error: pylab not intalled!")
return
116
117
118
119
120
121
122
123
E. Baeck
# list of lines. every element -> a line
lines = []
3.2. PROFILES, THIN WALLED APPROACH
124
125
126
127
128
129
130
Page 77
# over all elements
for e in self._elem:
if e is not None:
x1 = e._n[0]._x[0]
y1 = e._n[0]._x[1]
x2 = e._n[1]._x[0]
y2 = e._n[1]._x[1]
131
132
133
134
# add the line data into the list
lines += [ [ [x1,x2], [y1,y2] ], ]
#
--- a line ---------
135
136
137
138
# plot the lines
for line in lines:
pylab.plot(line[0],line[1],’b’)
# b: blue
# plot the lines nodes
for line in lines:
pylab.plot(line[0],line[1],’rp’)
# r: red p: point
139
140
141
142
143
144
145
# plot the title
pylab.title(self._name)
146
147
148
# plot it into a png-file
pylab.savefig(self._name + ".png")
149
150
151
# show viewer
if viewer: pylab.show()
152
153
154
3.2.7
# close the pylab
pylab.close()
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.
23.4.2015
Analysis of Structures - SS 15
Page 78
Base
list
Python’s build-in
list container
AList
− self. init (..): constructor
+ self.add(..): Add by index
The class AList is based on the
python build-in list class. The
Add method adds an object with a
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
5
6
’’’
extends the python’s buildin class List
to get a perfect array feeling
’’’
7
8
from Base import Base
9
10
class AList(Base,list):
11
12
13
14
# constructor
def __init__(self):
Base.__init__(self)
15
16
17
18
19
20
21
# add an instance like an array would do
# no : index
# ojb: object
def add(self,no,obj):
# check the length
ubound = len(self) -1
22
23
24
25
if no > ubound:
for i in range(ubound+1,no+1):
self += [None,]
26
27
28
# store it!
self[no] = obj
29
30
31
32
# print the list’s content
def list(self):
lobj = 0
# counter
33
34
35
36
E. Baeck
# iterate the container
for obj in self:
3.2. PROFILES, THIN WALLED APPROACH
Page 79
37
try:
38
obj.list()
except:
self.appendLog("object %d is unprintable" % lobj)
# pass
39
40
41
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
Base
Profile
1..*
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
3
4
5
6
7
8
9
’’’
check the Profile class
3
| :2
:1 |
1---2
’’’
import Profile
reload(Profile)
10
11
12
from Profile import Profile
from Element import Element
23.4.2015
Analysis of Structures - SS 15
Page 80
13
from Node
import Node
14
15
16
print ">> ProfileApp: check the Profile class"
p = Profile("L 100x50x6")
17
18
19
20
h
w
t
= 100.
= 50.
=
6.
21
22
23
24
25
# create Noints
n1 = Node(1,
-w,t/2.)
n2 = Node(2,-t/2.,t/2.)
n3 = Node(3,-t/2.,h)
26
27
28
29
# create elements
e1 = Element(1,n1,n2,t)
e2 = Element(2,n2,n3,t)
30
31
32
33
# add the elements
p.addElement(e1)
p.addElement(e2)
34
35
36
# calculate the section values
p.getResults()
37
38
39
# print profile’s data
p.list()
40
41
42
43
# view the profile and delete it
p.view()
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>> ProfileApp: check the profile class
19.45.04 |Name.................: L 100x50x6
19.45.04 | area...............:
8.6400 cmˆ2
19.45.04 | center of mass.....:
-10.67
35.67 mm
19.45.04 | 1st moments.....:
30.82
-9.22 cmˆ3
19.45.04 | 2nd moments ucs.:
200.25
25.52
-11.23 cmˆ4
19.45.04 | 2nd moments scs.:
90.32
15.68
21.65 cmˆ4
19.45.04 | 2nd moments mcs.:
96.14
9.86 cmˆ4
19.45.04 | rotation angle..:
15.06 deg, tan(a) =
0.269
19.45.04 | element
1, A=
1, B=
2, t=
6.000 L= 47.000 A=
282.000
19.45.04 | center............:
-26.500
3.000
19.45.04 | static moments....: 8.460e+02 -7.473e+03
19.45.04 | moments of inertia: 2.538e+03 2.499e+05 -2.242e+04
19.45.04 | node
1, y =
-50.000, z =
3.000
19.45.04 | node
2, y =
-3.000, z =
3.000
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
17
18
19
20
21
19.45.04
19.45.04
19.45.04
19.45.04
19.45.04
|
|
|
|
|
Page 81
center............:
-3.000
51.500
static moments....: 2.997e+04 -1.746e+03
moments of inertia: 2.000e+06 5.238e+03 -8.992e+04
node
2, y =
-3.000, z =
3.000
node
3, y =
-3.000, z =
100.000
Figure 3.12 shows the output of the
profile’s view method. First the picture is created, then a png file is written 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.
23.4.2015
Analysis of Structures - SS 15
Page 82
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
special features of an U-Profile,
i.e. the geometric parameters.
The class will be inherit the Profile class and will have the feature
to create this profile with an U
geometry.
+ self. w: with
+ self. s: web thickness
+ self. t: flange thickness
− self. init (..): constructor
+ self.list(..): list profiles values
+ 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
3
4
5
6
’’’
Implementaion of a UProfile class
’’’
from Profile import Profile
from Node
import Node
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
15
16
17
18
E. Baeck
self._h
self._w
self._s
self._t
=
=
=
=
h
w
s
t
#
#
#
#
height
width
web thickness
flansch thickness
3.2. PROFILES, THIN WALLED APPROACH
19
20
Page 83
# check input parameters
self.check()
21
22
23
# create the geomtry data
self.create()
24
25
26
27
# check the input parameters
def check(self):
dMin = 1.
28
29
30
31
32
33
34
35
36
37
# checking the parameters
if self._h < dMin:
raise Exception("invalid
if self._w < dMin:
raise Exception("invalid
if self._s < dMin:
raise Exception("invalid
if self._t < dMin:
raise Exception("invalid
height h: %e" % self._h)
width w: %e" % self._w)
thickness s: %e" % self._s)
thickness t: %e" % self._t)
38
39
40
# create the datastructure of an u-profile
def create(self):
41
42
43
hs = (self._h - self._t)/2.
ws = self._w - self._s/2.
44
45
46
47
48
49
# create the nodes
n1 = Node(1,0., hs)
n2 = Node(2,0.,-hs)
n3 = Node(3,ws, hs)
n4 = Node(4,ws,-hs)
50
51
52
53
54
# create the elements
e1 = Element(1,n1,n2,self._s)
e2 = Element(2,n1,n3,self._t)
e3 = Element(3,n2,n4,self._t)
55
56
57
58
59
3.2.10
# assign the elements
self.addElement(e1)
self.addElement(e2)
self.addElement(e3)
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.
23.4.2015
Analysis of Structures - SS 15
Page 84
The implementation of the testing environment is given in listing 3.11.
Listing 3.11: Implementation of a UProfile-Testing Environment
1
2
3
4
5
’’’
check the UProfile class
’’’
import UProfile
reload(UProfile)
6
7
from UProfile import UProfile
8
9
10
11
12
print ">> UProfileApp: check the profile class"
try:
#
name
h w s t
p = UProfile("U80",80,45, 6, 8)
13
# calculate the section values
p.getResults()
14
15
16
# print profile’s data
p.list()
17
18
19
# view the profile’s system
p.view()
20
21
22
23
24
25
26
# delete the instance
del p
except Exception,e:
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
>> UProfileApp: check the profile class
19.57.13 |Name.................: U80
19.57.13 | area...............:
11.0400 cmˆ2
19.57.13 | center of mass.....:
12.78
0.00 mm
19.57.13 | 1st moments.....:
0.00
14.11 cmˆ3
19.57.13 | 2nd moments ucs.:
105.75
39.51
0.00 cmˆ4
19.57.13 | 2nd moments scs.:
105.75
21.47
0.00 cmˆ4
19.57.13 | 2nd moments mcs.:
105.75
21.47 cmˆ4
19.57.13 | rotation angle..:
0.00 deg, tan(a) =
0.000
19.57.13 | element
1, A=
1, B=
2, t=
6.000 L= 72.000 A=
432.000
19.57.13 | center............:
0.000
0.000
19.57.13 | static moments....: 0.000e+00 0.000e+00
19.57.13 | moments of inertia: 1.866e+05 0.000e+00 0.000e+00
19.57.13 | node
1, y =
0.000, z =
36.000
19.57.13 | node
2, y =
0.000, z =
-36.000
19.57.13 | element
2, A=
1, B=
3, t=
8.000 L= 42.000 A=
336.000
19.57.13 | center............:
21.000
36.000
19.57.13 | static moments....: 1.210e+04 7.056e+03
19.57.13 | moments of inertia: 4.355e+05 1.976e+05 2.540e+05
19.57.13 | node
1, y =
0.000, z =
36.000
19.57.13 | node
3, y =
42.000, z =
36.000
E. Baeck
3.2. PROFILES, THIN WALLED APPROACH
22
23
24
25
26
27
28
Page 85
19.57.13 | element
3, A=
2, B=
4, t=
8.000 L= 42.000 A=
19.57.13 | center............:
21.000
-36.000
19.57.13 | static moments....: -1.210e+04 7.056e+03
19.57.13 | moments of inertia: 4.355e+05 1.976e+05 -2.540e+05
19.57.13 | node
2, y =
0.000, z =
-36.000
19.57.13 | node
4, y =
42.000, z =
-36.000
>> UProfileApp: stop
336.000
Figure 5.2 shows the output of the
profile’s view method. First the picture is created, then a png file is written 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. 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
2
3
# This script is executed only once, if the package is loaded.
# So we print a little to show what’s going on
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>
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
3
4
Note, that the file names are case sensitive although you may work on Windows plattform.
Note, if we do so, we also can move the total folder Profile into Pythons folder Lib/site-packages.
23.4.2015
Analysis of Structures - SS 15
Page 86
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
3
4
5
6
7
8
9
10
11
12
’’’
check the UProfile class
’’’
import Profile.UProfile
reload(Profile.UProfile)
# import total module
# reload total module
# make sure that’s the current
from Profile.UProfile import UProfile
# import from a package
# from here on every thing is the same...
print ">> UProfileApp: check the profile class"
try:
#
name
h w s t
p = UProfile("U80",80,45, 6, 8)
13
# print profile’s data
p.listData()
14
15
16
17
18
19
20
# delete the instance
del p
except Exception,e:
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.
dict
Python’s build-in dictionary class
ProfileDB
− self. init (..): constructor
The class ProfileDB is based on a
a dictionary. Profile instances are
are stored like in a database.
+ self.list(..): print instance’s data
Figure 3.16: UML-Diagram of the Profile Database
The code of the ProfileDB class is given below.
5
A dictionary is used to store instance pointers with an arbitrary access key.
E. Baeck
3.2. PROFILES, THIN WALLED APPROACH
Page 87
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
4
5
# The ProfileDB class should store arbitray profile objects in
# a dictionary. Therefore we inherit from the buildin dict object
class ProfileDB(Base,dict):
6
7
8
def __init__(self):
Base.__init__(self)
# call the Base constructor
9
10
11
12
13
14
15
16
17
18
19
20
# the List method calls the List method of it’s items
# if there is no item, the case is handled with an exception block
def list(self):
iobj = 0
# initialize the object counter
for name in self:
# iterate the keys of the dictionary
try:
# open the try block
self[name].list()
# try to list an object
except:
# if not possible log it to the log file
self.appendLog(" Error: No profile key %s found, slot %d" % \
(name,iobj))
iobj += 1
# increment the counter
21
22
23
24
25
26
27
28
29
30
31
32
# the View method calls the View method of it’s items with a False Flag.
# if there is no item, the case is handled with an exception block
def view(self):
iobj = 0
# initialize the object counter
for name in self:
# iterate the keys of the dictionary
try:
# open the try block
self[name].View(False)
# try to write the png file
except:
# if not possible log it to the log file
self.appendLog(" Error: No profile key %s found, slot %d" % \
(name,iobj))
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 .
23.4.2015
Analysis of Structures - SS 15
Page 88
Listing 3.15: Implementation of a Testing-Environment for the ProfileDB-Class
1
2
3
4
5
6
7
8
9
’’’
This testing example implements a little profile
database. Two U-profiles are created and stored in
the database. Then the whole content of the database
is printed using the AppendLog method of the base class
’’’
#
package module
class
from Profile.UProfile
import UProfile
from Profile.ProfileDB
import ProfileDB
10
11
12
13
# create Profile database
db = ProfileDB()
14
15
16
# create the instance of an U-Profile
prof = UProfile("U100",100.,50.,6.0,8.5)
17
18
19
# and save it into the db
db.setDefault("U100",prof)
20
21
22
# create the instance of an U-Profile
prof = UProfile("U140",140.,60.,7.0,10.)
23
24
25
# and save it into the db
db.setDefault("U140",prof)
26
27
28
# print the content of the db
db.list()
29
30
31
# print png files of the content of the db
db.view()
Figure 3.17: Pictures of the Profiles stored in the Database
E. Baeck
Part II
Scripting with Abaqus
89
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.
91
Page 92
4.2
Analysis of Structures - SS 15
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
4.3
Page 93
A Modeling Chain
Figure 4.2 shows how to create a Finite Element model in Abaqus/CAE. It
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,
which are created drawing a sketch.
Create Database
The only FE model parameter, which are created directly, are the material
properties and the section values. This properties are created within the
module Property. The properties are then assigned to the geometric objects
(lines, areas and volumes).
Module Part
Create a part and
assign the sketch
After having created a sketch the sketch has to be assigned to a part. If no
part exists, a part hast to be created. The properties (materials and section
data) are assigned to the sketches’ geometric objects.
Module Property
Create a properties, materials and sections, assign 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.
Loadcases are modeled in terms of load steps. So a new step has to be created as a container for loads and boundary conditions. Loads and boundaries are assigned to the geometric objects of the sketch which were assigned to a part before.
To create the mesh, the mesh’s control parameters should be configured and
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
calculate the results the job has to be submitted.
Module Sketch
Draw a sketch
Module Assembly
Create an instance and
assign the part to it
Module Step
Create a step as
container for a load case
Module Load
Create loads and
boundary condition 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
23.4.2015
Analysis of Structures - SS 15
Page 94
4.4
A little interactive Warm Up Example
In section 4.3 we have discussed the Abaqus modeling chain. Following 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
4.4.4
Page 95
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
23.4.2015
Analysis of Structures - SS 15
Page 96
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.
97
Analysis of Structures - SS 15
Page 98
(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.
mask =
X
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 99
(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.
23.4.2015
Analysis of Structures - SS 15
Page 100
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
2
# copy the next line into the abaqus command window and execute
# execfile("c:\\CM\\Cm-AoS\\WS1011\Abaqus\\3Trusses.py")
3
4
5
6
from abaqus import *
from abaqusConstants import *
from caeModules import *
# this we need for regionToolset
7
8
modelname = ’3Trusses’
9
10
11
12
13
14
15
# delete old database if exists
try:
del mdb.Models[modelname]
print "model ’%s’ deleted." % modelname
except:
print "No model ’%s’ found!" % modelname
16
17
18
19
import os
# os tools
os.chdir(r’c:\\cm\\Cm-AoS\\WS1011\\Abaqus’)
20
21
22
23
24
25
26
27
28
29
# set up parameters
dx
= 1000.
dy
= 1500.
A
= 13.5*100.
Fx
= -100000.
Fy
= -100000.
EMod = 210000.
nue = 0.3
#
#
#
#
#
#
#
length in x
length in z
U100 area
horzontal load
vertikal load
Young’s module
Poisson’s ratio
30
31
32
# (1) create a model
myModel = mdb.Model(name=modelname, modelType=STANDARD_EXPLICIT)
33
34
35
36
# (2) create a sketch
mySketch = myModel.ConstrainedSketch(name=’3Truss-Sketch’,
sheetSize=1.1*2*dy)
E. Baeck
5.1. 3 TRUSSES SCRIPT
Page 101
37
38
39
40
41
42
#
- create tuple with coordinates
xyPoint = ( (0,0), (dx,0), (dx,dy), (0,dy) )
#
- iterate the tuple and draw lines
for i in range(1,len(xyPoint)):
mySketch.Line(point1=xyPoint[0], point2=xyPoint[i])
43
44
45
46
# (3) create part
myPart = myModel.Part(name=’Trusse-Part-1’,
dimensionality=TWO_D_PLANAR, type=DEFORMABLE_BODY)
47
48
49
#
- assign the sketch
myPart.BaseWire(sketch=mySketch)
50
51
52
53
54
# (4) set up properties
#
- create material for steel
mySteel = myModel.Material(name = ’Steel’)
mySteel.Elastic(table=( (EMod,nue), ))
55
56
57
58
#
- create truss section
mySection = myModel.TrussSection(name=’Truss-Section’, area=A,
material=’Steel’)
59
60
61
62
63
64
65
66
#
- assign the section to all lines
alledges = myPart.edges
edges
= alledges.getSequenceFromMask(mask=(’[#7 ]’, ), )
region
= regionToolset.Region(edges=edges)
myPart.SectionAssignment(region=region, sectionName=’Truss-Section’, offset=0.0,
offsetType=MIDDLE_SURFACE, offsetField=’’,
thicknessAssignment=FROM_SECTION)
67
68
69
70
# (5) create an instance
root
= myModel.rootAssembly
myInst
= root.Instance(name=’Trusses-Instance’, part=myPart, dependent=ON)
71
72
73
74
# (6) create a load step
myModel.StaticStep(name=’First Step’, previous=’Initial’,
description=’Static Load Step’)
75
76
77
78
79
80
81
82
#
- create loads for the loadstep
v1
= myInst.vertices
verts1 = v1.getSequenceFromMask(mask=(’[#2 ]’, ), )
region = regionToolset.Region(vertices=verts1)
myModel.ConcentratedForce(name=’Load-1’,
createStepName=’First Step’, region=region, cf1=Fx, cf2=Fy,
distributionType=UNIFORM, field=’’, localCsys=None)
83
84
85
86
87
88
89
90
#
- create boundary conditions for the loadstep
verts1 = v1.getSequenceFromMask(mask=(’[#d ]’, ), )
region = regionToolset.Region(vertices=verts1)
myModel.DisplacementBC(name=’BC-1’,
createStepName=’First Step’, region=region, u1=0.0, u2=0.0, ur3=UNSET,
amplitude=UNSET, fixed=OFF, distributionType=UNIFORM, fieldName=’’,
localCsys=None)
91
92
# (7) create mesh
23.4.2015
Page 102
93
94
95
96
Analysis of Structures - SS 15
#
- number of elments / line
e
= myPart.edges
pickedEdges = e.getSequenceFromMask(mask=(’[#7 ]’, ), )
myPart.seedEdgeByNumber(edges=pickedEdges, number=1, constraint=FINER)
97
98
99
100
101
102
103
#
- set up the element type
elemType1 = mesh.ElemType(elemCode=T2D2, elemLibrary=STANDARD)
e
= myPart.edges
edges = e.getSequenceFromMask(mask=(’[#7 ]’, ), )
Region=(edges, )
myPart.setElementType(regions=Region, elemTypes=(elemType1, ))
104
105
106
#
- create the mesh
myPart.generateMesh()
107
108
109
#
- show the mesh
session.viewports[’Viewport: 1’].setValues(displayedObject=myPart)
110
111
112
113
114
115
116
117
118
119
120
# (8) create a job and submit it
jobname = modelname+’-Job-1’
myJob = mdb.Job(name=jobname, model=modelname,
description=’Calculation of the 3 Trusses System’, type=ANALYSIS,
atTime=None, waitMinutes=0, waitHours=0, queue=None, memory=50,
memoryUnits=PERCENTAGE, getMemoryFromAnalysis=True,
explicitPrecision=SINGLE, nodalOutputPrecision=SINGLE, echoPrint=OFF,
modelPrint=OFF, contactPrint=OFF, historyPrint=OFF, userSubroutine=’’,
scratch=’’)
myJob.submit(consistencyChecking=OFF)
121
122
123
#
- note: wait for completion, if the result values should be read form DB
myJob.waitForCompletion()
124
125
126
127
128
# (9) analysis of results
#
- open the database: odb file
myOdb = visualization.openOdb(jobname+’.odb’)
129
130
131
#
- read data from the last frame
frame = myOdb.steps[’First Step’].frames[-1]
132
133
134
135
136
137
138
139
#
- printing the displacements
data = frame.fieldOutputs[’U’]
n
= len(data.values)
print "%d Result records" % n
print ’--no ---ux----- ---uy----’
for value in data.values:
print "%4d %10.5f %10.5f" % (value.nodeLabel,value.data[0],value.data[1])
140
141
142
143
144
145
146
147
#
- printing the stresses
data = frame.fieldOutputs[’S’]
n
= len(data.values)
print "%d Result records" % n
print ’--no --S11-----’
for value in data.values:
print "%4d %10.5f" % (value.elementLabel,value.data[0])
148
E. Baeck
5.1. 3 TRUSSES SCRIPT
149
150
Page 103
# close the database
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
23.4.2015
Page 104
5.2
Analysis of Structures - SS 15
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 suppression 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
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.
The following steps of analysis should be done automated by the script.
q
L
Figure 5.4:
Girder
Single Span
• 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
5.2.2
Page 105
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.
23.4.2015
Analysis of Structures - SS 15
Page 106
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
+ self.s: profile’s web thickness
+ self.len: girder’s length
+ self.load: load to apply on girder’s top face
+ ... some attributes more
Only the most important
attributes are shown in the
diagram to get a compact
picture. All attributes are
given in the following table.
+ 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
load
kN
ymod
N/mm
nue
1
girder’s length
applied load
2
Young’s module
Poisson ratio
3
nue
kg/mm
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)
mass density (used for frequency analysis)
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 107
The following listing 5.2 shows the implementation of the class InputData.
Listing 5.2: Implementation of U-Girders’ InputData Class
1
2
# -*- coding: utf-8 -*__author__ = ’baeck’
3
4
5
#
module
content/class
from Base import Base
6
7
8
# input dataset
class InputData(Base):
9
10
11
# contructor method
def __init__(self):
12
13
14
# initialize Base-Data
Base.__init__(self)
15
16
17
18
19
# some constants like macros in C
self.LINEAR
= 0
# linear static calculation
self.BUCKLING
= 1
# stability analysis
self.FREQUENCY = 2
# frequency analysis
20
21
## dimensions: N, mm, s
22
23
24
25
26
27
28
## >> start
# parameter
self.h
self.w
self.t
self.s
user input data -of U100
= 100.
# data according to profile tables [mm]
= 50.
=
8.5
=
6.0
29
30
31
# system parameter
self.len
=
4.0
# length [m]
# material parameters
self.ymod
= 210000.
self.nue
= 0.3
self.rho
= 7.8e-6
# N/ m m Young’s module
# Poisson ratio
# mass density kg/ m m
# loads
self.load
# load in kN
32
33
34
35
36
37
38
39
= 10.
40
41
42
43
44
45
# mesh parameter (seeds)
self.maxElement = int(1000)
# element and node number of the
self.webSeed
= int(4)
# student version are restricted to 1000
self.flangeSeed = int(2)
# so we have to be carefull
self.lengthSeed = self.maxElement/(self.webSeed + self.flangeSeed*2 +1) -1
46
47
48
49
# step or calculation control
self.stepType
= self.LINEAR
self.stepNames = ("Linear","Buckling","Frequency")
50
51
52
# buckling input data
self.numBEigen
= 6
23.4.2015
Analysis of Structures - SS 15
Page 108
53
54
self.numBIterX
= 100
self.numBVectors = self.numBEigen + 10
55
56
57
58
59
60
# frequency input data
self.numFEigen
= 6
self.numFIterX
= 100
self.numFVectors = self.numFEigen + 10
## >> close user input data --
61
62
63
64
## project parameters
self.prjName
= "U-Girder"
self.jobName
= self.prjName;
65
66
67
# output control
self.bPngFiles = True
# flag to control the file export
68
69
70
# read the inputdata (till now not implemented)
self.read()
71
72
73
# calculate parameter values for the calculation
self.setHelpers()
74
75
76
# check the input data (till now not implemented)
self.check()
77
78
79
# calculate parameter values for the calculation
def setHelpers(self):
80
81
82
83
84
self.hs
=
self.ws
=
self.len *=
self.p
=
(self.h - self.t)/2.
self.w - self.s/2.
1000.
# length in [mm]
self.load/(self.ws*self.len)*1.e3
85
86
87
88
89
# check the calculations parameter
def check(self):
#> it’s your job!
pass
90
91
92
93
94
E. Baeck
# read the calculations parameter from a file
def read(self):
#> we’ll see, whether we will do it!
pass
5.2. U-GIRDER SCRIPT
5.2.4
Page 109
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
+ self.nodeRFo: reaction forces
+ self.nodeDis: node displacements
+ self.sumRFo: sum of reaction forces to check load balancing
The data containers we use
here are dictionaries, which
are using the node’s key as
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
2
# -*- coding: utf-8 -*__author__ = ’baeck’
3
4
5
6
7
8
’’’
container for result data
’’’
from math import fabs
from Base import Base
9
10
class ResultData(Base):
11
12
13
14
15
16
17
# constructor
def __init__(self):
self.nodePos = {}
self.nodeRFo = {}
self.nodeDis = {}
self.sumRFo = [0.,0.,0.]
#
#
#
#
to store the node coordinates and it’s label
to store the reaction forces
to store the node displacements
sum vector of the reaction forces
18
19
20
21
22
23
24
25
# calculate the maximum displacement along the center line
def getMaxDisp(self):
max = 0.
for label in self.nodePos:
disp = self.nodeDis[label]
if fabs(disp[1]) > max: max = fabs(disp[1])
return max
23.4.2015
Analysis of Structures - SS 15
Page 110
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
2
# -*- coding: utf-8 -*__author__ = ’baeck’
3
4
5
6
7
8
9
’’’
all common functions and variables
’’’
#
module
item
our name of this item
from datetime import datetime as time
import os
10
11
class Base():
12
13
14
__count = 0
# count the instances
__log
= "UGirder.log"
15
16
17
18
19
20
# constructor
def __init__(self,log = ""):
if log != "": Base.__log = log
Base.__count += 1
self.appendLog("instance %d created" % Base.__count)
21
22
23
24
# destructor
def __del__(self):
Base.__count -= 1
25
26
27
28
29
30
# reset all members, here a static method to work on class attributes
@staticmethod
def resetAll():
Base.__count = 0
os.remove(Base.__log)
31
32
33
34
35
# print into the log file
def appendLog(self,text):
t = time.now()
timestamp = "%2.2d.%2.2d.%2.2d |" % (t.hour,t.minute,t.second)
36
37
38
39
40
textout = timestamp + text
# print into the logfile
f = file(Base.__log,"a")
f.write(textout + "\n")
41
42
E. Baeck
print textout
5.2. U-GIRDER SCRIPT
5.2.6
Page 111
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
+ self.property: Abaqus property
+ self.instance: Abaqus instance
+ self.odb: Abaqus object database
Only the most important
attributes are shown in the
diagram to get a compact
picture.
+ 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
2
# -*- coding: utf-8 -*__author__ = ’baeck’
3
4
5
6
7
8
9
10
11
12
13
’’’
the girder’s main class
’’’
# for testing only, to be sure, that every modul will be compiled
import Base
reload(Base)
import InputData
reload(InputData)
import ResultData
reload(ResultData)
14
15
16
# UGirder imports
from Base
import Base
23.4.2015
Analysis of Structures - SS 15
Page 112
17
18
19
from InputData import InputData
from ResultData import ResultData
from math
import sqrt
20
21
22
23
24
# all abaqus imports
from abaqus
import *
from caeModules
import *
from abaqusConstants import *
25
26
27
# the UGirder class
class UGirder(Base):
28
29
30
31
32
# constructor
def __init__(self):
Base.__init__(self)
Base.resetAll()
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# references to Abaqus objects
self.input
= InputData()
self.result
= ResultData()
self.model
= None
self.sketch
= None
self.part
= None
self.materials
= []
self.properties
= []
self.instance
= None
self.odb
= None
self.viewport
= None
self.selectFlange = None
self.selectWeb
= None
47
48
49
50
51
52
53
54
55
56
57
# creates all used objects to create the FEM model
def createSystem(self):
self.createModel()
self.createPart()
self.createMaterials()
self.createProperties()
self.assignProperties()
self.createMesh()
self.getFiberNodes()
self.createInstance()
58
59
60
61
62
63
64
65
66
# creates the model instance
def createModel(self):
self.appendLog("create model...")
try:
del mdb.models[self.input.prjName]
except:
pass
self.model = mdb.Model(name=self.input.prjName)
67
68
69
70
# creates a part from a sketch
def createPart(self):
self.appendLog("create a part from a sketch...")
71
72
E. Baeck
# do a little abbreviation
5.2. U-GIRDER SCRIPT
73
Page 113
data = self.input
74
75
76
77
# create the sketch
self.appendLog("create sketch...")
sketch = self.model.ConstrainedSketch(name=data.prjName,sheetSize=data.h*2.)
78
79
80
81
# specify the polygon points
xyPoints = ( (data.ws , data.hs), (
0., data.hs) ,
(
0.,-data.hs), (data.ws,-data.hs) )
82
83
84
85
86
87
88
89
# create the lines
for i in range(1,len(xyPoints)):
msg = "Line %d: x1 = %10.3f y1 = %10.3f x2 = %10.3f y2 = %10.3f" % \
(i,xyPoints[i-1][0],xyPoints[i-1][1],
xyPoints[ i][0],xyPoints[ i][1])
self.appendLog(msg)
sketch.Line(point1=xyPoints[i-1],point2=xyPoints[i])
90
91
92
93
94
95
# create the part
self.part = self.model.Part(name=data.prjName,
dimensionality=THREE_D,
type=DEFORMABLE_BODY)
self.part.BaseShellExtrude(sketch=sketch,depth=data.len)
96
97
98
99
100
101
102
# creates the materials
def createMaterials(self):
self.appendLog("create materials...")
self.materials.append(self.model.Material(name="steel"))
self.materials[0].Elastic(table = ( (self.input.ymod, self.input.nue) ,) )
self.materials[0].Density(table = ( (self.input.rho, ) ,) )
103
104
105
106
107
108
109
110
111
112
113
# creates the properties
def createProperties(self):
self.appendLog("create properties...")
self.properties = []
self.model.HomogeneousShellSection(name="Flange",
material="Steel",
thickness=self.input.t)
self.model.HomogeneousShellSection(name="Web",
material="Steel",
thickness=self.input.s)
114
115
116
117
118
119
120
121
122
123
124
125
# assign the properties
def assignProperties(self):
self.appendLog("assign properties...")
data = self.input
self.selectFlange = self.part.faces.findAt(
( (data.ws/2., -data.hs,data.len/2.) ,),
( (data.ws/2., data.hs,data.len/2.) ,))
#usage of regionToolset:
#region = regionToolset.Region(faces = selectFlanges)
#myPart.SectionAssignment(region=region, ...)
self.part.SectionAssignment(region=(self.selectFlange,),sectionName="Flange")
126
127
128
# - Web
self.selectWeb = self.part.faces.findAt( ( ( 0., 0., data.len/2.) ,),)
23.4.2015
Analysis of Structures - SS 15
Page 114
129
self.part.SectionAssignment(region=(self.selectWeb,),sectionName="Web")
130
131
132
133
134
135
136
137
138
# creates the mesh
def createMesh(self):
self.appendLog("generate mesh...")
data = self.input
# - assign element type: S4R
elemType = mesh.ElemType(elemCode = S4R)
self.part.setElementType(regions=(self.selectFlange,self.selectWeb),
elemTypes = (elemType,))
139
140
141
142
143
144
145
146
# - assign seeds
#
o flange
select = self.part.edges.findAt( ( (data.ws/2., data.hs,
0.),
( (data.ws/2.,-data.hs,
0.),
( (data.ws/2., data.hs, data.len),
( (data.ws/2.,-data.hs, data.len),
self.part.seedEdgeByNumber(edges=select,number=data.flangeSeed)
),
),
),
),)
147
148
149
150
151
#
o web
select = self.part.edges.findAt( ( (0.,0.,
0.), ),
( (0.,0., data.len), ),)
self.part.seedEdgeByNumber(edges=select,number=data.webSeed)
152
153
154
155
156
157
158
#
o length direction
select = self.part.edges.findAt( ( (data.ws, data.hs, data.len/2.),
( (
0., data.hs, data.len/2.),
( (
0.,-data.hs, data.len/2.),
( (data.ws,-data.hs, data.len/2.),
self.part.seedEdgeByNumber(edges=select,number=data.lengthSeed)
),
),
),
),)
159
160
161
# generate mesh
self.part.generateMesh()
162
163
164
165
# searching for fiber nodes, i.e nodes on the center line
def getFiberNodes(self):
self.appendLog("find nodes on center fiber...")
166
167
168
# iterate the container (list: the data is given)
for node in self.part.nodes:
169
170
171
172
173
# calculate the distance of the node from the centerline
# precision = 1 mm
if (sqrt(node.coordinates[0]**2 + node.coordinates[1]**2) < 1.):
self.result.nodePos[node.label] = node.coordinates
174
175
176
177
178
179
180
181
182
183
184
E. Baeck
self.appendLog("%d elements created." % len(self.part.elements))
self.appendLog("%d nodes created." % len(self.part.nodes))
self.appendLog("%d nodes on the center line." % len(self.result.nodePos))
# print node coordinates on center line
# iterate the container (dictionary: -> the key is given)
self.appendLog("--no ---------x ---------y ---------z")
for label in self.result.nodePos:
node = self.result.nodePos[label]
self.appendLog("%4d %10.2f %10.2f %10.2f" % \
(label,node[0],node[1],node[2]))
5.2. U-GIRDER SCRIPT
Page 115
185
186
187
188
189
190
191
# create instance
def createInstance(self):
self.appendLog("create instance...")
self.instance = self.model.rootAssembly.Instance(name=self.input.prjName,
part=self.part,
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
1
2
3
4
5
6
7
8
9
10
11
12
13
# create step
def createStep(self,type):
self.appendLog("create step of type ’%s’..." % self.input.stepNames[type])
self.input.stepType = type
# first we have to delete an old created step, to clear the momory
if len(self.model.steps) > 1: del self.model.steps["Step-1"]
# then we create the new one
# create a linear static step with it’s data
if type == self.input.LINEAR:
self.model.StaticStep(name="Step-1",previous="Initial")
self.createBCs(type)
self.createLoads(type)
14
15
16
17
18
19
20
21
22
23
# create a buckling step
elif type == self.input.BUCKLING:
self.model.BuckleStep(name="Step-1",
previous="Initial",
numEigen
= self.input.numBEigen,
maxIterations = self.input.numBIterX,
vectors
= self.input.numBVectors)
self.createBCs(type)
self.createLoads(type)
23.4.2015
Analysis of Structures - SS 15
Page 116
24
25
26
27
28
29
30
31
32
33
# create a frequency step
elif type == self.input.FREQUENCY:
self.model.FrequencyStep(name="Step-1",
previous="Initial",
eigensolver=SUBSPACE,
numEigen
= self.input.numFEigen,
maxIterations = self.input.numFIterX,
vectors
= self.input.numFVectors)
self.createBCs(type)
34
35
36
37
38
39
40
41
42
43
44
45
# create BC for the U-girder
# stepIndex.: step index
def createBCs(self,stepIndex):
data = self.input
self.appendLog("create boudary conditions...")
select = self.instance.edges.findAt( ( (data.ws/2.,data.hs,
0.),),
( (data.ws/2.,data.hs,data.len),),)
self.model.DisplacementBC(name="vertical line BCs",
createStepName="Step-1",
region=(select,),
u2=0.0)
46
47
48
49
50
51
select = self.instance.vertices.findAt( ( (0.,data.hs,0.), ),)
self.model.DisplacementBC(name="rigid body mode BCs",
createStepName="Step-1",
region=(select,),
u1=0.0,u3=0.0,ur2=0.0)
52
53
54
55
56
57
58
59
60
61
62
63
# create loads on the top face of the U girder
# stepIndex.: step index
def createLoads(self,stepIndex):
data = self.input
self.appendLog("create loads...")
select = self.instance.faces.findAt( ( (data.ws/2.,-data.hs, data.len/2.), ),)
region = regionToolset.Region(side1Faces=select)
self.model.Pressure(name="flange pressure",
createStepName="Step-1",
region=region,
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
1
2
3
4
5
6
# submit and run the job
def runJob(self):
self.input.jobName = (self.input.prjName + "-%d") % self.input.stepType
self.appendLog("create job %s" % self.input.jobName)
job = mdb.Job(name=self.input.jobName,model=self.input.prjName)
7
8
9
10
E. Baeck
self.input.appendLog("submit job %s" % self.input.jobName)
job.submit()
job.waitForCompletion()
5.2. U-GIRDER SCRIPT
Page 117
Figure 5.10: Loads and Boundary Conditions
11
self.appendLog("job %s done" % self.input.jobName)
12
13
14
15
16
17
# open result database und assign it to the viewport
def openDatabase(self):
self.odbName = self.input.jobName + ".odb"
self.appendLog("open database file %s" % self.odbName)
self.odb = session.openOdb(self.odbName)
18
19
20
21
# set the viewport
self.viewport = session.viewports["Viewport: 1"];
self.viewport.setValues(displayedObject=self.odb)
22
23
24
25
26
27
28
29
# analyze the result data
def analyzeResults(self):
# set the font size of the legend
self.setFontSize(12)
# set the view perspective
self.viewport.view.setViewpoint(viewVector=(1, -0.25, -1),
cameraUpVector=(0, -1, 0))
30
31
32
33
34
35
36
self.input.stepType == self.input.LINEAR:
self.analyzeLinearStep()
elif self.input.stepType == self.input.BUCKLING:
self.analyzeBuckling()
elif self.input.stepType == self.input.FREQUENCY:
self.analyzeFrequency()
if
37
38
39
40
41
42
# analyze the linear static step
def analyzeLinearStep(self):
self.appendLog("analyze the linear static results")
data
= self.input
result = self.result
43
44
45
# calculte the sum of the reaction forces
self.result.sumRFo = [0.,0.,0.]
46
23.4.2015
Analysis of Structures - SS 15
Page 118
47
48
49
# - select results
#
|the last frame
frame = self.odb.steps["Step-1"].frames[-1]
50
51
52
53
54
55
56
57
58
59
60
# - select the reaction forces
rfo
= frame.fieldOutputs[’RF’]
# - over all nodes
for value in rfo.values:
# filter nodes with vanishing RFs
if (sqrt( value.data[0]**2
+ value.data[1]**2
+ value.data[2]**2 ) > 1.e-10):
result.nodeRFo[value.nodeLabel] = value.data
for i in range(3): result.sumRFo[i] += value.data[i]
61
62
63
64
self.appendLog("sum of the reaction forces: %12.3e %12.3e %12.3e" % tuple(result.sumRFo))
error = (data.load*1.e3 + result.sumRFo[1])/(data.load*1.e3)*100.
self.appendLog("error.....................: %12.3f %%" % error)
65
66
67
68
69
70
71
# iterate and print the RF container (dictionary: -> the key is given)
self.appendLog("--no ---------RFx ---------RFy ---------RFz")
for label in result.nodeRFo:
nodeRF = result.nodeRFo[label]
self.appendLog("%4d %12.3e %12.3e %12.3e" % \
(label,nodeRF[0],nodeRF[1],nodeRF[2]))
72
73
74
75
76
77
# - select the node displacements
dis
= frame.fieldOutputs[’U’]
# - over all nodes
for value in dis.values:
result.nodeDis[value.nodeLabel] = value.data
78
79
self.appendLog("maxium center displacement: %12.3e mm" % result.getMaxDisp())
80
81
82
# optionally create png-Files
if data.bPngFiles:
83
84
85
86
87
88
89
90
varList = ("U1","U2","U3")
for var in varList:
# plot into the viewport
self.viewport.odbDisplay.setPrimaryVariable(
variableLabel=’U’,
outputPosition=NODAL,
refinement=(COMPONENT,var))
91
92
93
94
# in colour on the system faces
self.viewport.odbDisplay.display.setValues(plotState=(CONTOURS_ON_DEF,))
self.viewport.view.fitView()
95
96
97
98
# print the image into a file
pngFile = data.prjName + "-" + data.stepNames[0] + "-" +var
self.printPngFile(pngFile)
99
100
101
102
E. Baeck
# analyze the buckling step
def analyzeBuckling(self):
self.appendLog("analyze the buckling step")
5.2. U-GIRDER SCRIPT
103
104
Page 119
data
= self.input
result = self.result
105
106
107
# over all eigenforms
for i in range(data.numBEigen):
108
109
110
111
112
113
# plot into the viewport
self.viewport.odbDisplay.setPrimaryVariable(
variableLabel=’U’,
outputPosition=NODAL,
refinement=(INVARIANT,’Magnitude’))
114
115
116
117
self.viewport.odbDisplay.display.setValues(plotState=(CONTOURS_ON_DEF,))
self.viewport.odbDisplay.setFrame(step="Step-1", frame=i+1)
self.viewport.view.fitView()
118
119
120
pngFile = data.prjName + "-" + data.stepNames[1] + ("-E%2.2d" % (i+1,))
self.printPngFile(pngFile)
121
122
123
124
125
126
# analyze the frequency step
def analyzeFrequency(self):
self.appendLog("analyze the frequency step")
data
= self.input
result = self.result
127
128
129
# over all eigenforms
for i in range(data.numFEigen):
130
131
132
133
134
135
# plot into the viewport
self.viewport.odbDisplay.setPrimaryVariable(
variableLabel=’U’,
outputPosition=NODAL,
refinement=(INVARIANT,’Magnitude’))
136
137
138
139
self.viewport.odbDisplay.display.setValues(plotState=(CONTOURS_ON_DEF,))
self.viewport.odbDisplay.setFrame(step="Step-1", frame=i+1)
self.viewport.view.fitView()
140
141
142
pngFile = data.prjName + "-" + data.stepNames[2] + ("-E%2.2d" % (i+1,))
self.printPngFile(pngFile)
143
144
145
146
147
148
149
150
151
152
# set the fontsize
# - size....: font size in [pt]
def setFontSize(self,size):
fsize = int(size*10)
self.viewport.viewportAnnotationOptions.setValues(
triadFont=’-*-verdana-medium-r-normal-*-*-%d-*-*-p-*-*-*’ % fsize,
legendFont=’-*-verdana-medium-r-normal-*-*-%d-*-*-p-*-*-*’ % fsize,
titleFont=’-*-verdana-medium-r-normal-*-*-%d-*-*-p-*-*-*’ % fsize,
stateFont=’-*-verdana-medium-r-normal-*-*-%d-*-*-p-*-*-*’ % fsize)
153
154
155
156
157
158
# print the viewports content into a png file
# - pngFile...: file name
# - myViewport: data
def printPngFile(self,pngFile):
session.printOptions.setValues(vpBackground=ON)
23.4.2015
Analysis of Structures - SS 15
Page 120
session.printToFile(fileName=pngFile, format=PNG,
canvasObjects=(self.viewport,))
159
160
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
5
6
7
’’’
we can start the script using the followning command:
execfile(r’[path]\mainUGirder.py’)
execfile(r’c:\unidue\CM\Cm-AoS\AOS-BookOfExamples\Py\Code\Abaqus\UGirder\mainUGirder.py’)
’’’
8
9
10
11
# set the workdirectory
import os
os.chdir(r’c:\unidue\CM\Cm-AoS\AOS-BookOfExamples\Py\Code\Abaqus\UGirder’)
12
13
14
15
# for testing only
import UGirder
reload(UGirder)
16
17
18
# import UGirder and it’s friends
from UGirder import UGirder
19
20
21
22
# create the geometric system, the mesh
sys = UGirder()
sys.createSystem()
23
24
25
26
27
28
29
# create steps, run job and analyse
for i in range(3):
sys.createStep(i)
sys.runJob()
sys.openDatabase()
sys.analyzeResults()
E. Baeck
5.2. U-GIRDER SCRIPT
5.2.7.1
Page 121
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
23.4.2015
Analysis of Structures - SS 15
Page 122
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 123
Figure 5.13 shows the buckling modes 4 uto 6.
Figure 5.13: Buckling Modes 4 to 6
23.4.2015
Analysis of Structures - SS 15
Page 124
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 125
Figure 5.15 shows the dynamic modes 4 uto 6.
Figure 5.15: Dynamic Modes 4 to 6
23.4.2015
Page 126
E. Baeck
Analysis of Structures - SS 15
Part III
Appendix
127
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
2
3
# forced reload for the developer step
import InputData
# this binds the module to the symbol
reload(InputData)
# now we reload in any case
4
5
6
7
# from InputData import InputData
from InputData import InputData
# this is our standard import
data= InputData()
129
Page 130
E. Baeck
Analysis of Structures - SS 15
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
eµ · dA ≈
A=
A
with: Li
ti
eµ,i
B.1.2
n
X
eµ,i · Li · ti
(B.1)
i=1
the length of line i
the thickness of line i
the relative elasticity of line i (1 for only one material)
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
eµ · z · dA ≈
Sy =
A
Z
eµ · y · dA ≈
Sz =
A
with: Ai
yi
zi
n
X
i=1
n
X
eµ,i · z i · Ai
eµ,i · y i · Ai
i=1
the area of a line i
the y coordinate of the center of line i
the z coordinate of the center of line i
131
(B.2)
Analysis of Structures - SS 15
Page 132
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
2
eµ · z · dA ≈
Iy =
n
X
A
Z
n
X
A
eµ,i ·
(yb,i − ya,i )2 /12) + y 2i · Ai
i=1
n
X
Z
eµ · y · z · dA ≈
Iyz =
A
with: Ai
yi
zi
ya,i
za,i
yb,i
zb,i
(zb,i − za,i )2 /12) + z 2i · Ai
i=1
eµ · y 2 · dA ≈
Iz =
eµ,i ·
eµ,i · (((yb,i − ya,i )(zb,i − za,i )/12) + y i · z i ) · Ai )
(B.3)
i=1
the area of a line i
the y coordinate of the center of line i
the z coordinate of the center of line i
the y coordinate of the first point of line i
the z coordinate of the first point of line i
the y coordinate of the second point of line i
the z coordinate of the second point of line i
R
To solve an integral like Iy = A z 2 · dA for a polyline we can split up the integral into the sum of
integrals over the polyline segments.
Z
Iy =
A
z 2 · dA =
n Z
X
i=1
z 2 · dA
(B.4)
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 133
Thus we make the following substitution.
(y, z) ⇒ (η, ξ)
(B.5)
z = ξ/cos(ϕ)
(B.6)
With this substitution we will get the following integral.
Z
η=+t Z ξ=+L/2
Iy,i =
ξ2
· dη · dξ
cos(ϕ)2
η=−t
ξ=−L/2
Z ξ=+L/2
ξ2
=t·
· dξ
cos(ϕ)2
ξ=+L/2
ξ3
1 = t·
·
3 cos(ϕ)2 ξ=−L/2
ξ=−L/2
=t·
L3
1
·
12 cos(ϕ)2
(zb,i − za,i )2
=
· Ai
12
B.1.4
with t · L = Ai
(B.7)
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
=
A
dA
R A
z · dA
Sy
zc = AR
=
(B.8)
A
A dA
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)
23.4.2015
Analysis of Structures - SS 15
Page 134
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
−2 · Iyz,c
1
· arctan(
)
2
Idel
1
Iη = · (Isum + Isqr )
2
1
Iξ = · (Isum − Isqr )
2
ϕ=
1
(B.10)
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
135
Analysis of Structures - SS 15
Page 136
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 137
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.
23.4.2015
Analysis of Structures - SS 15
Page 138
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 abbreviations (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.)
139
Page 140
E. Baeck
Analysis of Structures - SS 15
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.
141
Analysis of Structures - SS 15
Page 142
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)
z, c ∈ C
with
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
2
3
import matplotlib.pyplot as plt
from functools import partial
from TimeCheck import TimeCheck
# is used to show the results
# to create a one dimensional function
# performance checker
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# calculation of one mandelbrot row
def mandelbrotCalcRow(yPos, h, w, max_iteration = 1000):
y0 = yPos * (2/float(h)) - 1
# rescale to -1 to 1
row = []
for xPos in range(w):
x0 = xPos * (3.5/float(w)) - 2.5 # rescale to -2.5 to 1
iteration, z = 0, 0 + 0j
c = complex(x0, y0)
while abs(z) < 2 and iteration < max_iteration:
z = z**2 + c
iteration += 1
row.append(iteration)
return row
18
19
20
21
22
23
24
# creates a set of calculations
def mandelbrotCalcSet(h, w, max_iteration = 1000):
partialCalcRow = partial(mandelbrotCalcRow, h=h, w=w,
max_iteration = max_iteration)
mandelImg = map(partialCalcRow, xrange(h))
return mandelImg
25
26
27
28
29
30
# main program calling the mandelbrot calculations
# create the timecheck object
s = TimeCheck()
# and set current time
s.set()
31
32
# run the mandelbrot calculation
E. Baeck
E.2. A MULTI-PROCESSING POOL
33
34
35
Page 143
mandelImg = mandelbrotCalcSet(400, 400, 1000)
# print the performance data
s.get("single processor performance")
36
37
38
39
plt.imshow(mandelImg)
plt.savefig(’mandelimg.png’)
# plt.show()
Listing E.2: Output for a i7 Processor
1
E.2.2
21.912
: single processor performance
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
2
3
4
import multiprocessing
import matplotlib.pyplot as plt
from functools import partial
from TimeCheck import TimeCheck
#
#
#
#
is used to get multi processor support
is used to show the results
to create a one dimensional function
performance checker
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# calculation of one mandelbrot row
def mandelbrotCalcRow(yPos, h, w, max_iteration = 1000):
y0 = yPos * (2/float(h)) - 1
# rescale to -1 to 1
row = []
for xPos in range(w):
x0 = xPos * (3.5/float(w)) - 2.5 # rescale to -2.5 to 1
iteration, z = 0, 0 + 0j
c = complex(x0, y0)
while abs(z) < 2 and iteration < max_iteration:
z = z**2 + c
iteration += 1
row.append(iteration)
return row
19
20
21
22
23
24
25
# creates a set of calculations and distributes it onto 4 processors
def mandelbrotCalcSet(h, w, max_iteration = 1000):
# make a helper function that better supports pool.map by using
# only 1 parameter
partialCalcRow = partial(mandelbrotCalcRow, h=h, w=w,
max_iteration = max_iteration)
26
27
28
# creates a pool of process, controls worksers
pool =multiprocessing.Pool(processes=4)
29
30
31
32
33
34
35
# the pool.map only accepts one iterable, so use the partial function
# so that we only need to deal with one paramter.
# the pool method map runs the set in parallel
mandelImg = pool.map(partialCalcRow, xrange(h))
pool.close()
# we are not adding any more processes and close
pool.join()
# tell it to wait until all threads are done before going on
36
23.4.2015
Analysis of Structures - SS 15
Page 144
return mandelImg
37
38
39
40
# check, if thread is main tread!
if __name__==’__main__’:
41
# main program calling the mandelbrot calculations
# create the timecheck object
s = TimeCheck()
# and set current time
s.set()
42
43
44
45
46
47
mandelImg = mandelbrotCalcSet(400, 400, 1000)
# print the performance data
s.get("quadcore performance")
48
49
50
51
# show result image
plt.imshow(mandelImg)
plt.savefig(’mandelimg.png’)
52
53
54
Listing E.4: Output for a i7 Processor
1
9.941
: quadcore performance
We see that the function mandelbrotCalcRow in both cases is the same.
One difference is, that in multi processor case we use the pool and it’s map.
Another difference is, that, if the pyfile 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 distribution needs a lot of power. This
comes from the fact, that the python
interpreter has to load the file multiple, which should be executed in parallel. If the calculation really splits up
into independent cycles, we would expect nearly a factor of 4 instead of 2.
Figure E.1: Mandelbrot Set
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
2
3
# - create png-files of the displacement components u1, u2, u3 (x,y,z)
varlist = ("U1","U2","U3")
for var in varlist:
4
5
6
7
8
9
# - plot the results into the window
myViewport.odbDisplay.setPrimaryVariable( \
variableLabel=’U’, outputPosition=NODAL,
refinement = (COMPONENT,var))
myViewport.view.fitView()
10
11
12
13
14
15
# - and then into an png-file
pngfile = prjname + "-" + var
session.printOptions.setValues(vpBackground=ON)
session.printToFile(fileName=pngfile, format=PNG,
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
2
3
4
5
session.viewports[’Viewport: 1’].viewportAnnotationOptions.setValues(
triadFont=’-*-verdana-medium-r-normal-*-*-100-*-*-p-*-*-*’,
legendFont=’-*-verdana-medium-r-normal-*-*-100-*-*-p-*-*-*’,
titleFont=’-*-verdana-medium-r-normal-*-*-100-*-*-p-*-*-*’,
stateFont=’-*-verdana-medium-r-normal-*-*-100-*-*-p-*-*-*’)
145
Analysis of Structures - SS 15
Page 146
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
F.2
Page 147
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 viewport "Viewport: 1". It’s view member provides a method to specify the directions discussed above.
1
2
session.viewports[’Viewport: 1’].view.setViewpoint(viewVector=(1, -1, 1),
cameraUpVector=(0, -1, 0))
23.4.2015
Page 148
E. Baeck
Analysis of Structures - SS 15
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
149
Index
:, 31
Abaqus
area, 133
arithmetic mean, 135
as, 17
abaqusMacros, 99
BaseWire, 100
close, 102
ConstrainedSketch, 100
DisplacementBC, 101
Basic, 24
bit’s values, 19
break, 28
bytecode, 5
element type
T2D2, 101
elemType, 101
fieldOutputs, 102
frame, 102
generateMesh, 101
getSequenceFromMask, 100
instance, 100
job, 101
material, 100
mesh, 101
model, 99
openOdb, 102
part, 100
regionToolset, 101
rootAssembly, 100
SectionAssignment, 100
seedEdgeByNumber, 101
session, 101
setElementType, 101
StaticStep, 101
step, 102
submit, 101
TrussSection, 100
values, 102
vertices, 101
viewport, 101
visualization, 102
waitForCompletion, 101
C, 5, 19, 23, 24, 27
C#, 5
Camel Case, 15
center of mass, 135
Charles Simonyi, 15
chdir, 99
class
AList, 75, 79
Base, 67
Element, 71
Node, 69
Profile, 75
ProfileDB, 88, 89
UProfile, 75, 84
classes, 55
code blocks, 25
complement, 18
ComTypes, 7
constructor, 55
continue, 28
cos, 17
count, 41
datetime, 48
day, 48
def, 31
derivative, 36
destructor, 56
dictionary, 42, 88
append, 41
Aptana, 137
e/E format, 23
150
INDEX
except, 81
exception, 84
extend, 41
f format, 23
factorial, 27
factorial(170), 28
factorial(400), 28
file
close, 51
open, 50
read, 51
write, 50
Finite Element Model, 95
first moment, 133
float, 24
font size, 147
for, 27
FORTRAN, 5
Fortran, 24
Page 151
MacOS, 138
main axis, 136
Mandelbrot Set, 143
Mandelbrot/Multi Processor Solution, 145
Mandelbrot/Single Processor Solution, 144
map, 42
mathplotlib, 46
microsecond, 48
minute, 48
moment of inertia, 134
month, 48
Monty Python, 5
name, 24
negative number, 18
Newton, 35
Newton’s Algorithm, 39, 62
now, 48
NumPy, 7
OOP, 53, 107
g/G format, 23
global variables, 26
hour, 48
Hungarian Notation, 15
IDE, 137
if, 32
import, 17
indent, 25
index, 41
insert, 41
int, 24
Interactive window, 13
iteration, 36
Java, 5
Java Code Conventions, 141
legend, 147
Lib, 6
Lib/site-packages, 87
LIFO, 42
Linux, 138
list, 40, 41, 51
Logging, 52
long, 24
package, 17, 87
Parameters, 31
Performance-Checker, 49, 58
pi, 17
pop, 41
printf, 23
private, 55, 56
push, 42
PyDev, 137
pylab, 46
PythonWin, 12
raise, 84
random, 46
Random Numbers, 46
readlines, 51
remove, 41
reserved words, 16
return, 31
reverse, 41
SciPy, 9
second, 48
second moment, 134
Setup, 6
23.4.2015
Page 152
sin, 17
site-packages, 6
sort, 41
stack, 42
strings, 40
Sun Microsystems, Inc., 15
The Beatles, 42
timedelta, 48
Tkinter, 75
try, 81
tuple, 31, 40
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
Analysis of Structures - SS 15