In structural engineering - but not only there - it is often necessary to perform and document lengthy calculations. Therefore a tool would be useful that

• has sufficient numerical capabilities for simple engineering calculations - preferably with physical units,

• can be extended with user supplied routines,

• makes it easy to interact with other engineering applications or old, well tested code,

• generates nicely formatted output of the calculation for documentation and error-checking purposes,

• lets the user include things like chapters, table of contents, remarks, pictures and tables, references and so on.

PEng - short for Python for Engineers - is a Python based package that aims at addressing the above needs. PEng uses Python and the freely available mathematical library 'Scientific' to do the numeric work. Output can be generated via LaTeX, which offers the user a broad range of formatting possibilities. The resulting document is a pdf-file. For basic use of PEng you do not need prior knowledge of Python or LaTeX.

I am neither an expert in Python nor in LaTeX, or in object oriented programming. Therefore suggestions and comments from your side are very welcome.

# Installation

## For Linux and Windows users

• Python - PEng was written and tested using Python 2.4 but you can use Python 2.5 as well

• ScientificPython - 'ScientificPython is a Python library for common tasks in scientific computing.' as it says http://dirac.cnrs-orleans.fr/plone/software/scientificpython/ where you can get this fine piece of software. The version I work with is 2.4.9. PEng uses ScientificPython for doing computations with physical quantities.

• Numeric - This package is used by 'ScientificPython' and can be downloaded from http://numpy.scipy.org/. In case you encounter problems: For Python 2.5 users there is a special edition of Numeric on the ScienificPython website.

• PLY (Python Lex-Yacc) - is a compiler-compiler that PEng uses to understand what the user input is supposed to mean. Can be downloaded from http://www.dabeaz.com/ply/. Installation: at a command-prompt (for Windows users: 'Start/Execute/' and type 'cmd' or use IPython instead) move to the directory to where you extracted ply and type 'python setup.py install' (or '%run setup install' from within IPython)

## For Windows users

• PyReadline - If you want to have coloured output in the console Window of Windows you need PyReadline which is available at http://ipython.scipy.org/moin/PyReadline/Intro. Make sure to get the latest version - at least 1.4.4. It provides the colors of the colored output in the command window.

• ctypes - the package 'PyReadline' relies on the 'ctypes' package that can be obtained from http://python.net/crew/theller/ctypes/. It is already included in Python 2.5.

• MikTex - is an implementation of TeX on Windows and in charge of transforming the LaTeX, output of PEng into a nicely formatted pdf-document. It is available at http://miktex.org/. Restart your computer after installation so that the environment variable settings made by MikTex take effect. When you run MikTex with PEng for the first time, MikTex will inform you that additional packages have to be installed. For downloading them from the internet press the 'change' button, then select 'Packages shall be installed from the internet' and choose a server from the list presented to you. In case of problems try again but change the server.

## For Linux users

• texlive - PEng if preconfigured to use 'texlive' for producing pdf-files. If you want to change this take a look at the file 'PEngDoc.py' and edit the line where 'pdflatex' is called. Contrary to its behaviour under Windows PEng does not start a pdf-viewer automatically after having written the pdf-file to disc. It is probably best to use a viewer with automatic detection of changes. For example run the viewer 'gv' from the command prompt by typing 'gv --watch &'

If you have succeeded in downloading and installing the above software go to the 'PEng'-directory and type 'python setup.py install' at the command-prompt. Windows users can install PEng by double-clicking the executable installer instead.

# Examples

The project data - see section 'Download' - contains examples for Linux- and Windows users.

• FirstExample.py, SecondExample.py: The cummulated examples from the documentation
• PunchingShear.py: An example for a punching shear calculation.
• RCBeam.py: An example for calculating the necessary reinforcement area for a reinforced concrete beam under bending and normal force.

The examples are distributed in the hope that they will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

# Documentation

This documentation is also available as .pdf- and .tex-file from the project page - see section 'Download'.

## Hello World

In order to use PEng in a Python script include the following

import PEng
doc = PEng.Doc(namespace=globals())

'doc' is the object that processes your equations. The dictionary handed over to the parameter 'namespace' is the place where all calculation variables live. In case you use 'globals()' these variables are directly accessible from the surrounding Python code.

In order to have something calculated and output add

doc.calc("a=1")
doc.text("Hello World")
doc.texify()

save as 'FirstExample.py' and run the script. This results in these additional files located in the directory of 'FirstExample.py':

• FirstExample.txt - a text representation of the calculation.

• FirstExample.tex - a TeX version of the results document

• FirstExample.pdf - the pdf-file containing the calculation which is automatically loaded to a pdf-viewer in case you have installed one.

• FirstExample.aux, FirstExample.out, FirstExample.log - These are files generated by MikTex. The log-file contains a report regarding the generation of the pdf-file and is useful for error tracking.

The file 'FirstExample.py' as well as others can be found in the example directory of this distribution. Due to different unicode encodings there are separate versions of the example files for Linux and Windows.

When working with PEng two kinds of error may occur: Python and LaTeX errors. If the Python script is incorrect nothing will be generated. Instead an error message is shown in the window of the command prompt. This message includes a PEng generated diagnosis as well as a printout of the program stack. From the first line of that printout you can detect the line-number of the command that caused the error. In case that there is some error in the TeX -file MikTex will refuse to generate the pdf-file. Should this happen you can either resort to the messages generated by MikTex in the log-file or load the offending TeX-file into a TeX-editor (e.g. WinEdt) and use its error-detecting capabilities.

The name of the file to be processed is given to MikTex via a command line argument. For this to work the filename must not contain blanks - otherwise a warning is issued and nothing happens.

When starting a script by double-clicking on it the console-window with the error message will be closed before you get a chance of reading anything. In order to prevent this run the program from a command prompt or an integrated development environment such as IPython.

## doc.calc()

### Multiple lines, blanks and comments

The method 'calc()' or shorter 'c()' of the doc-object is used to evaluate formulas and include them in the final calculation document. The string handed over to calc() may contain several lines:

doc.calc(ur"""
# This is a comment
a=1 # This is also a comment
b=2
c=3
""")

All text in a line following '#' is ignored. Empty lines or blanks between the formulas or their components have no impact on the output.

The letters 'ur' preceding the multi-line Python string make it a unicode raw string: This means that a '\' need not be escaped like in normal Python strings and that unicode characters (e.g. 'ü','ö' or 'ä' and so on) can be included. In case you want to have non-ascii characters in your text be sure to add

# python
# -*- coding: mbcs -*- #

on Windows machines and

# python
# -*- coding: utf-8 -*- #

under Linux at the beginning of the file. This sets the kind of encoding to be used so that your unicode characters are correctly processed.

### Equation arrays

If one line has to accommodate more than one expression these are separated by semicolons. Such a sequence of expressions is evaluated from left to right:

doc.c(ur"""
a_1=1; a_2=10; a_3=100
b_1=2; b_2=20; b_3=200
c_1=3; c_2=30; c_3=300
""")

When executing the above you may notice from inspection of the pdf-file that the formulas handed over to a calc-command are aligned by their '='-signs and positioned in an array like structure like this:

### Naming conventions for variables

Variable names must start with a letter and may contain any number of letters (only ascii), digits, dots or underscores. Dots are used to select variables that are properties of an object. PEng is case sensitive with respect to variable names. Therefore 'A' and 'a' designate different things. When transforming the calculation to LaTeX the part of the variable names that follows the first underscore is printed as an index. Any underscores following the first one are printed as commas:

doc.c(ur"""
a_1_1 = a_1*b_1*c_1
""")

results in:

As you can see PEng by default not only outputs the final result of a formula but also what the formula looks like with all variables replaced by their values. This lets you familiarize with the numbers you actually work with and helps you detect situations where you have unknowingly redefined a variable somewhere along the way.

### Physical units

Sometimes it is useful to have physical units attached to the numbers: Firstly it spares you from making unit conversions and secondly it helps to unveil errors in formulas that are due to incompatible physical dimensions:

doc.c(ur"""
A=50[cm2];h=30[cm]
A*h
""")

comes out as

Physical properties are defined by writing the unit in squared brackets immediately after the value - no blanks allowed in between. Units of the form 'property**N' may be abbreviated with 'propertyN' (e.g. 'm**2' and 'm2' mean the same thing). For numbers with units operations like multiplication, subtraction, and raising to integer powers are allowed without restriction. In case you want a quantity to be raised to a non-integer power you have to make sure that the result can be represented by integer powers of the base units. Angular functions like sin(), cos() or tan() expect the type of their argument to be either '[deg]' or '[rad]'. If a plain number is given as function argument '[deg]' is used by default. For defining mirco-strains you can use a unit such as [mm/m].

### Built-in operators and mathematical functions

This is the list of available functions and operators that can be used within the calc-string:

• '+','-','*','**','^': basic mathematical operators. Instead of '**' a '^' may be used to raise some value to the power of some other value.
• sqrt(x), sqr(y): square root of x and square of y
• sin(x), cos(x), tan(x), 'cot(x)': angular functions
• asin(x), acos(x), atan(x), atan2(x,y), acot(x): inverse angular functions. The function $atan2(x,y)$ is somewhat special. It returns the angle corresponding to atan(x/y) taking into account the signs of both x and y
• abs(x): the absolute value of x
• exp(x): ex
• ln(x), log(x): natural logarithm of x
• log10(x): base 10 logarithm of x
• int(x): integer part of x
• min(x1, x2, ... , xn), max(x1, x2, ... , xn): minimum and maximum of the values x1 to xn

### Greek letters

PEng automatically converts the following parts of variable names to their greek equivalent:

For example:

doc.c(ur"""
alpha_beta_gamma=1
""")

results in

### Conditions

Often one has to ensure that the result of an equation meets a certain condition. PEng provides the usual comparison operators. The following lines

doc.c(ur"""
1==1; 1>0; 2>=1; 1<2; 1<=2; 1<>2
1==2; 1>2; 2>=3; 2<2; 3<=2; 1<>1
""")

give this output:

Search the results document for the phrase 'Error' to find any violated conditions.

### Adding text within equation arrays

Sometimes the name of a variable is not sufficient to clarify its meaning. In such situations pictures (see further below) or additional remarks are useful. These must be of the form "text" or 'text':

doc.c(ur"""
'text1'; a=1; "text2"
b=2;c=3;d=4
""")

he starting position of a text is aligned with the '='-signs of the formulas. The above code results in

### Format options for equations

Number format specifiers: The readability of the calculation output improves by limiting the results precision to some meaningful number of digits. This can be done for each expression individually or by setting a default value for the whole document. It is to be noted that the actual values used in the calculation are in no way influenced by the number format.

The line below shows how the number format '.2f' ('.2f' means that the number is to be printed in floating-point format with two digits precision. For further information in formatting numbers see the Python manual) is chosen for the results of two assignments. The options to be applied follow at the end of each expression and are inclosed in curly brackets:

doc.c(ur"""
a = 1.2345 {.2f}
b = 1.2 {.2f}
""") 

comes out as

In the first case the result is truncated to '1.23' as expected. The result of the second assignment is not changed though. This reflects the rule that PEng only applies a number format if the resulting number-string is shorter than the original one. This aims at preventing the impression of excessive accuracy. Therefore 1.2 is not transformed to '1.20'.

As mentioned above number formats can be set for the whole document:

doc.c(ur"""
{.2f}
{[cm],.2f};{[m],.1f}
""")

doc.c(ur"""
a = 1.2345
b = 1.2
c = 1.2345 [cm]
d = 1.2345 [m]
""")

results in

If no unit is supplied the format specifier is the default for all values without units. As shown above a global default value format can be defined for each unit as well.

Further formatting options for equations: Formatting options are situated at the end of an expression being enclosed in curly brackets. If more than one option is to be used these have to be separated from each other by ','. Besides controlling the output format of numbers PEng offers these additional options:

• '=', '==' or '===': This sets the number of steps shown when evaluating an expression. With '=' only the result is shown, '==' limits the output to the equation with variable names and the result and '===' makes PEng output the formula with variable names, values and result. Leaving out the leading expression sets the document default.
• '/', '//' or '///': Same as the above except that each expression component starts in a new line. This is useful for long formulas that do not fit in one line.
• '-': The equation is evaluated but no output is written to the results document.
• {label}: Can be used to define a label for the corresponding equation. By typing 'a=1 {\label{foo}}' the label 'foo' is defined throughout the document and the equation gets a number. If you want to reference that equation later on in the text use 'see formula \ref{foo}'.
• <"text" , "text":
• Adds text immediately before or after the equation. For example:
doc.c(ur"""
e=a*b{=,<'\Rightarrow ','\Rightarrow '}
""")
results in

The keyword \Rightarrow is borrowed from LaTeX. The given text belongs to the equations-environment in LaTeX. Therefore non-ascii-characters will not be printed by default.

## doc.text()

Text can but need not be part of an equation array. For longer passages of pure text use the method .text() of object doc. Like .calc it accepts multi-line strings with or without the preceding letters 'ur' which mark unicode raw strings:

doc.text(ur"""
This is text with unicode letters 'äöüß'
on \\ two
lines
""") 

comes out as

Notice that carriage returns in the calculation file have no impact in the results document. Use '\\' for this purpose when generating LaTeX output. The command .text() may be abbreviated as .t().

Any text may contain LaTeX-commands. In order to mark a text as being a chapter heading write '\section{text}'. Go further down the chapter hierarchy by using '\subsection{text}' or '\subsubsection{text}'. From these chapter headings a table of contents can be generated automatically - see further below.

## doc.texify()

This makes the doc-object build txt, tex and pdf-files of the calculation processed so far. These files are stored in the same directory under the same name - yet different extension - as the Python-script from which they originate. In addition to this - when runnning on a Windows machine - the pdf-file is loaded to a pdf-viewer if such an application is available on your system.

Under Windows I have not worked out a satisfying solution to reloading a pdf-file that is already displayed. Therefore close the pdf-viewers window of a document before texifying it again. Otherwise you will get an error message telling you that the pdf-file could not be written to disc because of another application using the file at the same time.

## doc.flush()

builds all output files just like texify() does. However MikTex is not started and therefore no pdf-file generated. The command flush() can be useful if you want to have a quick look at the computation and the txt-file is sufficient for that.

## doc.list()

The command list(n) Shows the last 'n' lines of the output on screen. If 'n' is omitted all of the output will be shown.

## doc.picture()

Lets the user choose a picture and picture heading to be included in the calculation. The following parameters should be provided:

• path: path to the picture which may be given absolute or relative. MikTex can handle the PDF, JPG, and PNG graphics formats.
• caption: caption of the figure. The example below shows how to define a label for the picture by including the LaTeX-statement '\label{foo}' in the caption text. This lets you reference the figure from anywhere in the document by using '\ref{foo}':
doc.picture(path = House.jpg',
caption = '\label{house} This is a house',
width = '10cm')
doc.text('Figure \ref{house} shows a house')
• angle: angle of rotation of the picture in [deg]. If omitted 'angle=0' is the default.
• width: width of the picture (if an angle is given the picture is first rotated then scaled for width). Can be of the form "width=10cm" or "width = r'1.00 /textwidth'". The latter makes the picture stretch across the whole text area. See a LaTeX manual for further possibilities of defining a pictures width.
• additional parameters: Besides the parameters mentioned above the LaTeX statement 'includegraphics' accepts others as well. In the example below
doc.picture(path='Example.pdf',
caption = ur'\label{Example 1} Caption of example 1',
width = r'1.00 \textwidth', page = '2')
the parameter 'page' is set to a value of two. This extracts the second page of the pdf-file 'Example.pdf' and places it as a picture in the results document.

## doc.table()

It is sometimes a good idea to present a set of values in a table. PEng provides the command table() for these occations. The following example shows how this can be done in PEng. The code

doc.table(tablecaption = ur'caption',
tablehead = ur'col1 & col2 & col3 \\ \hhline{===}',
tabletail = ur'\hline \multicolumn{3}{r}{next page...} \\',
tablelasttail = ur'\hline',
lineappend = ur'\hline',
columnformat = ur'c|c|c',
cols = [[1,4], [2,5], [3,6]])

results in this output:

The parameters of the table-command have the following meaning:

• tablecaption: text written above the table. The LaTeX-command '\label{foo}' can be included so that the table can be referenced from somewhere in the document by writing '\ref{foo}'.
• tablehead: specifies the text written above each column. The column headings are separated by '&'. In the above example the part '\\ \hhline{===}' results in two horizontal lines below each of the three column headings
• tabletail: in case of tables that stretch over more than one page this text is written before each pagebreak
• tablelasttail: gets appended at the end of the table
• lineappend: is added at the end of each line of the table. In the above example '\hline' results in horizontal lines between the table entries
• columnformat: determines the horizontal justification of the entries in each of the table columns. Valid descriptors are 'c' for centered, 'r' for right aligned and 'l' for left aligned. In order to have vertical lines between columns include the sign '|'.
In case of columns with numbers readability improves by aligning these values by their fraction point. In LaTeX (by means of the dcolumn package) this can be done by writing 'D..{n}' as the format information for a column. 'n' is the maximum number of decimal places after the fraction point the column has to accommodate. Numbers with more than n fractional digits will overwrite neighboring cells. Using a negative number for n sets the column width according to the maximum width of the column entries. The code segment
doc.c("""a=sqrt(2){.3f}
b=sqrt(3){.3f}""")
doc.table(tablecaption = ur'caption',
tabletail = ur'\hline \multicolumn{1}{r}{next page...} \\',
tablelasttail = ur'\hline',
lineappend = ur'\hline',
columnformat = ur'|D..{3}|',
cols = [[a.number_str, b.number_str]]) 

thus results in

In the above example the command '\multicolumn{...}' makes the column heading centered.
When building the data for the table the property .number_str of the calculation variables was used to get a correctly formatted string representation of 'a' and 'b'.
• cols: Is a list of the columns of the table.
• lines: Instead of a list of columns the table data may be provided as a list of table lines.

PEng generates tables in LaTeX by use of the supertabular environment. For further details on this see the LaTeX documentation.

## Changing the LaTeX document settings

Every LaTeX file consists of two parts: first the initial settings that name the packages and parameters to be used for the whole document. After this comes the text body. By default PEng uses the file "Default_Latexheader_Windows.tex" or "Default_Latexheader_Linux.tex" - depending on the operating system your are working on - in the directory . There are two different headers for Linux and Windows because of the different standard encoding used for unicode characters ("utf-8" in Linux, "newansi" in Windows).

In case you want to define your own LaTeX -header provide a file named "LatexHeader.tex" in the directory of the PEng document to be associated to it. In this way it is possible to influence the documents layout. The "LatexHeader.tex"-file listed below will result in project information being printed at the top of each page of the calculation document.

\documentclass[fleqn]{article}
\usepackage{amssymb}
\usepackage{amsfonts}
\usepackage{amsmath}
\usepackage[ansinew]{inputenc} % now you can include 'äöüß' directly in the text
\usepackage{ae,aecompl}
\usepackage[a4paper, DIVclassic]{typearea}
\usepackage[pdftex]{graphicx}
\usepackage[ngerman]{babel}
\usepackage{fancyhdr}
\usepackage{color}
\definecolor{darkblue}{rgb}{0,0,.5}
\usepackage{hyperref}
urlcolor=darkblue}

\setlength\mathindent{1pc}  %identationlength for formulas

% ---
% here comes the project information:
% ---
No: 00000 } \chead{foo - bar - baz \\
Civil Engineering Company
Someone/00 } \lfoot{ {\tiny \today} }
\renewcommand\headrule{\vspace{-8pt}\dotfill}

Do not let yourself get confused by the above. Instead see the example in the directory 'Example3' for further help. It shows how to introduce a chapter structure in documents and generate a table of contents from it. References, labels, bibliography and citations are also included. The tex-version of the file you are currently reading can be found in the directory 'Documentation'.

One thing you should be aware of is that there are some special characters in LaTeX one has to escape when using them in text: these are '&', '%', '#', '_', '\$', '{' and '}'. Prefix them with '\'. The sign '\' has to be expressed by '\textbackslash' followed by a blank.

LaTeX introduces linebreakes by using an internal algorithm. In case you want to force a linebreak write '\\'. A new paragraph can be started by leaving one line empty. The first word of the new paragraph will then be somewhat shifted to the right.

Keywords that make LaTeX do something start with '\' and have their arguments enclosed in curly brackets. For example:

doc.t(ur"""\textbf{This is boldface text}""")

results in

For further information on LaTeX resort to one of the many textbooks available or search the internet.

## The PEngNum object

As mentioned in section 'Getting Started' the calculation variables live in the dictionary provided by the user when generating the PEng-document. Therefore writing

doc = PEng.Doc(namespace=globals())

makes the variables reside in the global namespace. These variables are objects of type PEngNum. Besides their value they contain additional information about the entity like name or format specifications. As the class PEngNum defines routines for most of the special methods (see the Python documentation for details) its objects can be used in the same way as integer or float variables. Mixing is also possible. See the file 'PEngNum.py' for details

## How PEng does what it does

The following is a short explanation of the main structure of PEng. I made use of the design patterns Parser, Builder and Composite (see Design Patterns)

The main object in PEng is PEngDoc: It stores references to the parser, the builders, calculation source file and variable namespace.

On initialization PEngDoc creates the parser object of type PEngParser and configures it with builders. These builders provide the functionality that PEngParser uses to generate output in different formats: PEngBuilderNum for calculating results, PEngBuilderPlainText for text, PEngBuilderLatex for tex-files, PEngBuilderScreenOutput for text with color-escape sequences. In order to make it easy to add new builders all building functionality is provided to PEngParser via the composite builder class PEngBuilderComposite.

# Development

The current (23 Aug 2008) version is 0.165a.

If you find any bugs, please send them to cpreisinger at users.sourceforge.net.

In case you have a good idea about how to improve the usability of PEng or the readability of this documentation please do not hesitate to give me notice.

clemens