Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
91 views

Manual Mesh Module

mesh
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
91 views

Manual Mesh Module

mesh
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 97

Report TVSM-5187

MESHING AND VISUALISATION


ROUTINES IN THE PYTHON VERSION
OF CALFEM

ANDREAS EDHOLM

Structural
Master’s Dissertation
Mechanics
Department of Construction Sciences
Structural Mechanics

ISRN LUTVDG/TVSM--13/5187--SE (1-86)


ISSN 0281-6679

MESHING AND VISUALISATION


ROUTINES IN THE PYTHON VERSION
OF CALFEM

Master’s Dissertation by
ANDREAS EDHOLM

Supervisor:
Jonas Lindemann, PhD,
LUNARC, Lund

Examiner:
Ola Dahlblom, Professor,
Div. of Structural Mechanics

Copyright © 2013 by Structural Mechanics, LTH, Sweden.


Printed by Media-Tryck LU, Lund, Sweden, February 2013 (Pl).

For information, address:


Division of Structural Mechanics, LTH, Lund University, Box 118, SE-221 00 Lund, Sweden.
Homepage: http://www.byggmek.lth.se
Preface

I would like to thank project supervisor Jonas Lindemann for the suggestions and feedback
provided by him during this project.

Lund, February 2013

Andreas Edholm
Abstract

This report is the result of a masters project conducted at the Division of Structural Mechan-
ics at Lund University. The purpose of the project was to integrate a FEM mesh generator
with the Python version of the code library CALFEM and improve the mesh visualisation
capabilities of said library. This report describes how the mesher software Gmsh and the visu-
alisation library visvis were integrated with CALFEM for Python. It also describes the three
Python modules pycalfem GeoData, pycalfem mesh, and pycalfem vis that were created as
part of the project.
Contents

1 Introduction 5
1.1 Software related to this project . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2 Problem description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2 Development 7
2.1 Integration of mesh generation tools . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2 Development of visualisation functions . . . . . . . . . . . . . . . . . . . . . . 8

3 Implementation 11
3.1 Minimal example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.2 pycalfem GeoData . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.3 pycalfem mesh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.4 pycalfem vis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.5 Example scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.6 Other changes to CALFEM for Python . . . . . . . . . . . . . . . . . . . . . . 30

4 Performance test 33

5 Differences between Gmsh and the meshing modules 37


5.0.1 Geometry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
5.0.2 How to make quadrangular elements . . . . . . . . . . . . . . . . . . . 40

6 Conclusions 41

7 Future Work 43

8 Example Case 45
8.1 The script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
8.1.1 Defining the geometry . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
8.1.2 Meshing the geometry . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
8.1.3 Solving the problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

3
CONTENTS CONTENTS

8.1.4 Visualising the results . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

A Examples 55
A.1 Mesh Ex 01.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
A.2 Mesh Ex 02.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
A.3 Mesh Ex 03.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
A.4 Mesh Ex 04.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
A.5 Mesh Ex 05.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
A.6 Mesh Ex 06.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
A.7 Mesh Ex 07.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
A.8 Mesh Ex 08.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
A.9 Mesh Ex 09.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
A.10 Mesh Ex 10.py . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83

B Status of existing CALFEM functions 89

4
Chapter 1

Introduction

1.1 Software related to this project


CALFEM The work in this project consists of additions to the code library CALFEM for
Python. The name stands for “Computer Aided Learning of the Finite Element Method”,
and its purpose is to serve as a learning tool for students of FEM. It was originally developed
for FORTRAN and later redeveloped into a MATLAB toolbox.[1] Later still a Python version
was developed by Andreas Ottosson in 2009 as part of his masters thesis at Lund University.[2]
The Python modules for CALFEM are named pycalfem and therefore the Python version
of CALFEM is sometimes informally called “PyCALFEM”.

Triangle Triangle is a FEM mesh generator for 2D triangular meshes. It is the meshing
tool that is used in the older meshing routines in both the MATLAB and Python versions
of CALFEM. It can create triangular meshes from 2D geometry with holes. Triangle is
developed by Jonathan Richard Shewchuk.[3]

Gmsh Gmsh is a 3D finite element grid generator.[4] It is developed by Christophe Geuzaine,


Jean-François Remacle and other contributors. It is used in the new meshing module de-
scribed in this report.
Gmsh has a large set of features. It has a graphical interface that users can use to create
and mesh geometry. Geometry can also be generated from scripts that can be written by
hand. The scripts have file extension geo. Meshed geometry produces msh-files that contain
nodes, elements, and other information about the FEM mesh.
Gmsh can be executed, and told to mesh geometry in geo-files, via the command-line.
This is how Gmsh is used in this project.
Apart from these features Gmsh also has post-processing and visualisation features that
were not used in this project.

Visvis Visvis is a graphical plotting library for Python.[5] It is an object oriented library
built on top of OpenGL. It has some syntactic similarities to MATLAB, and is able to

5
1.2 Problem description Introduction

plot in both 2D and 3D. It can draw 3D meshes and can easily be extended with custom
drawable objects. Visvis is dependent on the libraries Numpy and PyOpenGL. It also needs
a supported GUI backend, such as wxPython or PyQt.

1.2 Problem description


The project was divided into three goals; Meshing, visualisation, and general improvements.

Meshing The original mesh generation capabilities of CALFEM were weak. It could only
use Triangle, which is only capable of generating 2D meshes with triangular elements.
The first priority of this project was therefore to find and incorporate an alternative
meshing tool that could be used in the same way as Triangle, but with greater capabilities.
The mesher tool had to be executable from a Python script, and be able to mesh all the
element types available in CALFEM, which includes 3D hexahedral elements.
Since Triangle was neatly incorporated in CALFEM it was decided to attempt to make
user-interaction with the new mesher as similar as possible to the way Triangle was used, i.e.
it should be called with a function that returns the same data structures as trimesh2d, which
is the function that meshes using Triangle.

Visualisation The biggest issue with the visualisation functionality in CALFEM for Python
was that the draw functions assumed that the mesh consists of either 2D line elements of
triangle elements. This meant that other element types could not be drawn.
Another issue was that all drawing was done in a pop-up window that could not be
embedded in graphical user interfaces. The reason for this was that drawing functions were
in the class ElementView, which inherits from wx.Frame. wx.Frame is a class in the wxPython
GUI library and represents windows. This meant that it was impossible to embed graphs
drawn with ElementView in other windows. It also meant that users had to use wxPython if
they wanted to plot results with the built-in functions.
The second goal was to improve the visualisation capabilities of CALFEM for Python,
so that all available element types could be drawn and so that graphs could be embedded in
different GUI libraries.
At the beginning of the project it was decided that in order to solve these issues the
existing draw functions would need to be remade, or a new set of draw functions would need
to be written.

Improvements The final goal was to implement functionality that already existed in
CALFEM for MATLAB but was not yet implemented in Python. In particular, the missing
functions listed in appendix F of the original CALFEM for Python masters thesis[2] were to
be implemented. This goal was of low priority, and was only to be done if the other two goals
were completed within reasonable time.

6
Chapter 2

Development

The plan was to develop the parts of project in the order described in the previous chapter, i.e.
meshing first, then visualisation, and finally general improvements to CALFEM for Python
if any time remained. Due to the expected high reliance on external libraries, which had not
been evaluated before the project started, it was very difficult to determine what functionality
was possible to include, and how long it would take to implement functionality missing in
the libraries. it was therefore decided early on to not write a formal requirements document.
Another reason for this was because the goal was to match the functionality of CALFEM for
MATLAB, so it could serve as a guideline and minimum requirements document.

2.1 Integration of mesh generation tools


The first objective was to implement a mesher. The obvious solution was to use an existing
mesher program, of which there were many. There were a handful of requirements that such
a mesher would have to fulfil. The requirements were:

• Must be callable from the command-line or otherwise be able to communicate with


python programs.
• Must be able to mesh all the element types that CALFEM can handle.
• Must work in 2D and 3D.
• Must be free to use without licensing costs.
• Must be able to mesh geometry with holes.
• Optional: A graphical user interface. Especially if geometry can be built in the GUI.
• Optional: Easy to use.

In order to find such a mesher an online list of mesh generation software was consulted.[6]
It was found that only the grid generator Gmsh fulfilled all requirements.
CALFEM for MATLAB already had a set of functions for meshing geometry. Early
on in development this MATLAB-mesher was considered a guideline for the direction of
development of the new mesher. It was soon dropped when it became apparent that the
design ideas in the MATLAB-mesher did not work very well in Python or with Gmsh. The

7
2.2 Development of visualisation functions Development

idea of storing geometry data in structs (the MATLAB equivalent of Python dictionaries)
was taken and developed into the class GeoData, but otherwise there are few similarities.
The new meshing functionality went through a couple of iterations before it arrived at its
current shape. The class GeoData was not planned initially. It was created after it was decided
that it was not enough to represent geometry with dictionaries or lists, as in MATLAB and
the older Python function trimesh2d had done. The reason was that Triangle took geometry
that consisted of points and straight lines, which could be represented with two lists, while
Gmsh could take many different sorts of curves, surfaces and volumes.
The classes GeoData and GmshMesher were written to make this plethora of choices easily
accessible. Since Gmsh geometry can be fairly complex, it has many restrictions on how to
define geometry in the correct way. For example, there are “line loops” that are used for
defining the boundaries of surfaces, and these line loops must be constructed from curves
that are directed in a counter-clockwise fashion. It seemed like it would be a cumbersome
chore for users to keep all these line loops and curves in mind, so GmshMesher was written
so that it would automatically take care of such things. This is described in more detail in
the Results section.

2.2 Development of visualisation functions


As mentioned, the visualisation functionality in CALFEM for Python had many issues. One
of the issues was the drawing required a wxPython GUI, which meant that no other GUI
library could be used. The first plan was to simply rewrite the existing class ElementView so
that it was based on the wxPython Panel class instead of the Frame class. This would make
plots embeddable in wx GUIs. ElementView could then be rewritten for other GUI libraries
so that those other libraries could be used instead of wxPython.
That approach had some big flaws. The biggest being that rewriting the drawing code
to different libraries would be time-consuming and lead to much duplicate code. It was
therefore decided to instead write new drawing functions using an external plotting library
rather than attempt to rewrite the existing functions. The plotting library would need to
fulfil the following criteria:

• Able to draw triangles and quads with different-coloured faces and interpolated vertex
colouring.
• Able to draw splines, B-splines, and ellipse arcs. Alternatively, plot arbitrary curves
in 2D and 3D. This would be necessary in order to draw the different curve types that
Gmsh can handle.
• Few library dependencies. This would be important on school computers where users
might not have the administrative right to install new libraries.
• Embeddable in atleast wxPython and PyQT.
• Optional: Faster than ElementView.

In order to find such a library the internet was searched. Many libraries fulfilled some of
these criteria. Matplotlib and Mayavi were good candidates that missed one or two important

8
Development 2.2 Development of visualisation functions

criteria. In the end, graphics library visvis was chosen because it fulfilled all of the above
criteria.
Visvis is a Python library with a plotting syntax similar to MATLAB. Because of this it
was decided to avoid new classes and instead use convenience functions that work similarly
to the MATLAB plotting functions. The functions that were written are described in the
next chapter, in the pycalfem vis section.

9
Chapter 3

Implementation

The results of the project are three new modules called pycalfem GeoData, pycalfem mesh,
and pycalfem vis. There were also a few additions to the module pycalfem and some example
scripts that explain how to use the new modules.
Figure 3.1 contains a diagram of the dependencies of the new modules in CALFEM for
Python. Similarly, figure 3.2 has a diagram of the classes. Note that “private” classes,
functions, or attributes are not included in the diagrams, neither are external modules or
libraries. This means that, for example, the dependency of pycalfem vis on the library visvis
is not shown.

Figure 3.1: Dependencies between the new modules pycalfem GeoData, py-
calfem mesh, and pycalfem vis in CALFEM for Python

11
3.1 Minimal example Implementation

Figure 3.2: Class diagram of the new classes. The squares with tabs on the top
are modules. Only “public” methods, attributes, and the functions that are called
by the classes are shown.

3.1 Minimal example


Before describing the new modules in detail, here is a simple example of them in use. In the
example we use all the three modules and the library visvis to create, mesh, and draw some
geometry. The geometry is a flat triangle.
We begin by using addPoint to create three points at xy-coordinates (0, 0), (5, 0), and
(2.5, 4). These points are automatically assigned ID numbers, starting from 0.
Then we connect the points with three splines (in this example the splines are straight
lines). The first parameter of addSpline is a list of point IDs that the spline connects. The
other parameter seen here is marker, which is used for marking curves so that boundary
conditions may be applied later. Like the points, our splines are automatically assigned ID
numbers.
The last step of creating geometry is adding a surface with addSurface. The parameter is
a list of curve IDs that define the outer boundary of the surface.

12
Implementation 3.1 Minimal example

Then we can create a GmshMesher object. Its parameters are the GeoData object g, the
file path to the executable file gmsh.exe, and a size factor that determines the size of the
elements. For this example we assume that gmsh.exe is placed in a folder called gmsh in
the current working directory (typically the same as our python script). Meshing is done by
calling the create method, which returns the mesh in the shape of coords, edof, dofs, bdofs,
and elementmarkers.
Drawing geometry is done by calling the function drawGeometry. We also call the visvis
function figure, which opens a new figure window and sets it to the current figure, so that
the next drawing is not done in the same window.
We draw the mesh by calling drawmesh. It has four necessary parameters. These are the
node coordinate coords, the element topology edof, the number of dofs per node dofsPerNode,
and the element type elType. Element type 2 is triangle (3 is quadrangle).
Finally, it is necessary to make the script enter the application loop of a GUI back-end. If
this is not done the figures that have been plotted will disappear when the script terminates.
The two final lines of code make visvis find a GUI back-end and enter its application loop.
import pycalfem_GeoData
import pycalfem_mesh
import pycalfem_vis as pcv
import visvis as vv

g = pycalfem_GeoData.GeoData()

g.addPoint([0 , 0]) #0
g.addPoint([5 , 0]) #1
g.addPoint([2.5, 4]) #2

g.addSpline([0, 1]) #0
g.addSpline([1, 2]) #1
g.addSpline([2, 0], marker=10) #2

g.addSurface([0,1,2])

mesher = pycalfem_mesh.GmshMesher(geoData = g,
gmshExecPath = "gmsh/gmsh.exe"
elSizeFactor = 0.15)

coords, edof, dofs, bdofs, elementmarkers = mesher.create()

pcv.drawGeometry(g) #Draw geometry


vv.figure() #create new figure window
pcv.drawMesh(coords=coords, edof=edof, dofsPerNode=1, elType=2)

app = vv.use() #Get application object


app.Run() #Run app main loop.

13
3.2 pycalfem GeoData Implementation

Figure 3.3: Plot of the geometry of the minimal example.

Figure 3.4: Plot of the mesh of the minimal example.

3.2 pycalfem GeoData


The module pycalfem GeoData is fairly straight-forward in purpose and structure. It contains
a single class, GeoData, that simply holds the geometric data of a model. The user builds

14
Implementation 3.2 pycalfem GeoData

geometry by calling methods like addPoint, addSpline, addSurface, etc. These methods do
some (limited) checks on input to make sure it is correctly formatted.
Apart from geometry, the class also keeps track of markers and ID-numbers of all geometric
entities.
The purpose of the class is to make construction of geometry as easy as possible for the
user. The mesher Gmsh is much more complicated than the old mesher Triangle. However,
it should still be easy to create simple geometry. By hiding the representation of the geom-
etry behind adder- and remover-methods, the user can interact with the data without full
knowledge of how it is represented. It also means that the representation can be changed in
the future without breaking existing programs.

Class GeoData
Attributes
GeoData objects have a the following “public” attributes:
• points
• curves
• surfaces
• volumes
• is3D
Even though they are not prefixed by an underscore to mark them as private these at-
tributes should not be accessed by the user directly. Instead, the user should add, remove
and query geometric entities by calling the various methods in GeoData. The reason they are
“public” is because they are directly accessed by the GmshMesher class and the pycalfem vis
module.

Methods
These are the methods, grouped by functionality:
• addPoint(coord, ID=None, marker=0, elSize=1)
Method addPoint adds a point to the geometry. The only parameter that must be defined
is coord, which should be a lists of two or three coordinates. If three coordinates are given
GeoData will assume that the model is in 3D, which among other things makes the coordinates
of the mesh 3D.
ID is the ID number of this entity. It must be a non-negative integer. If no ID is supplied
the point will be given an ID, starting from 0.
The parameter marker is used for specifying in which region an entity is.
Parameter elSize sets the preferred element size at this point. Users can set this to make
the mesh more or less dense at different points. Mesh density may also be controlled with
the parameters elSizeFactor, minSize and maxSize of the GmshMesher constructor.

15
3.2 pycalfem GeoData Implementation

• addSpline(points, ID=None, marker=0, elOnCurve=None, elDistribType=None, elDistrib-


Val=None)
• addBSpline(points, ID=None, marker=0, elOnCurve=None, elDistribType=None, elDistrib-
Val=None)
• addCircle(points, ID=None, marker=0, elOnCurve=None, elDistribType=None, elDistrib-
Val=None)
• addEllipse(points, ID=None, marker=0, elOnCurve=None, elDistribType=None, elDistrib-
Val=None)

These methods add curves to the geometry model. All curves share the same pool of ID-
numbers, so users should not assign the same ID to a Spline and a Circle, for example.
The parameter marker is used for specifying in which region an entity is. When GmshMesher
meshes geometry, dofs on this region will be placed in the return value dictionary bdofs so
that users may apply boundary conditions.
The parameters elOnCurve, elDistribType, elDistribVal are used for structured meshes. Pa-
rameter elOnCurve sets the number of elements on the curve. If elOnCurve is defined the curve
counts as a “structured” curve and can be used as a boundary curve on structured surfaces.
The other two parameters define how the elements are distributed along the curve. elDis-
tribType can have values “bump” or “progression”. “Bump” means elements are denser or less
dense near the middle of the curve, while “progression” means elements are larger the further
along the curve they are. elDistribVal should be a float with value typically around 0.1 to 2.0.
For example, if elDistribType = “progression” and elDistribVal = 1.1 the sides of each
element will be 1.1 times that of the element that precedes it on the curve.

• addSurface(outerLoop, holes=[], ID=None, marker=0)


• addRuledSurface(outerLoop, ID=None, marker=0)
• addStructuredSurface(outerLoop, ID=None, marker=0)

These methods create surfaces from lists of curve IDs. The parameter outerLoop is a list of
curve IDs that define the outer boundary of the surface.
Method addSurface creates a flat surface that can have holes in it. The parameter holes
is a list of lists of curve IDs and define inner holes on the surface.
Conversely, addRuledSurface and addStructuredSurface make curved surfaces. The differ-
ence between the two is that addStructuredSurface takes a list of four structured curves, while
addRuledSurface can use three or four curves that do not have to be structured.
The parameter marker is used for specifying in which region an entity is. When GmshMesher
meshes geometry in 2D, apart from adding nodes to bdofs, elements in this region will be
placed in the list elementMarkers so that users may look up which marker a given element
has. Users can use this information to set different properties (such as thickness or thermal
conductivity) to elements in different regions.

• addVolume(outerSurfaces, holes=[], ID=None, marker=0)


• addStructuredVolume(outerSurfaces, ID=None, marker=0)

16
Implementation 3.2 pycalfem GeoData

These methods create volumes from lists of surface IDs. The parameter outerLoop is a list of
surface IDs that define the outer boundary of the volume.
The differences between the two functions are that addVolume can make arbitrary volumes
with internal cavities (holes), while addStructuredVolume must use six structured surfaces and
may not have holes. I.e. it creates hexahedral “super elements”.
Parameter marker is used for specifying in which region an entity is. When GmshMesher
meshes geometry in 3D, elements in this region will be placed in the list elementMarkers so
that users may look up which marker a given element has.

• setPointMarker(ID, marker)
• setCurveMarker(ID, marker)
• setSurfaceMarker(ID, marker)
• setVolumeMarker(ID, marker)

These methods let the user specify markers after entities have been constructed.

• removePoint(ID)
• removeCurve(ID)
• removeSurface(ID)
• removeVolume(ID)

These four methods remove the entity with the given ID. As mentioned, all curves share the
same ID pool. Same for surfaces and volumes.

• getPointCoords(IDs=None)

This method returns a list of coordinates of the points specified in IDs, which is a list of
integers. Each row of the returned list contains another list with the x, y, and z coordinates
of the point.

• pointsOnCurves(IDs)
• stuffOnSurfaces(IDs)
• stuffOnVolumes(IDs)

These methods get the geometric entities that exist on some other entity. For example,
pointsOnCurves(5) returns a list containing the point IDs of the points that define curve 5.
The oddly named stuffOnSurfaces and stuffOnVolumes return more lists. The IDs of every
subentity is returned. For example, stuffOnVolumes(8) returns three lists with IDs of the
subentities that make up volume 8: One list of points, one list of curves, and one list of
surfaces.

17
3.2 pycalfem GeoData Implementation

Internals
Attributes

GeoData has an attribute is3D which is False by default, but is set to True if addPoint is
called with the parameter coord as a list of three values.
Internally, when any of the add* methods are called, the parameters are processed (to
make sure they have valid values) and inserted in one of the object attributes points, curves,
surfaces, or volumes. These attributes are dictionaries containing nested lists. The keys to
these dictionaries are the entity IDs.
The purpose of representing geometric attributes in this way is to make the meshing code
in GmshMesher cleaner and easier to read. In one way this is bad design, because much of
the logic of the routines that write geo-files is built into the structure of GeoData.
For example, the values in the dictionary points are lists that look like:

[[x, y, z], elSize, marker]

I.e. a point is a list of three elements; A list of float coordinates, a float element size, and
an integer marker. Note that the names are not attribute names, only comments that make
it easier to remember which indices represent what.
Similarly, curves is a dictionary whose elements look like:

[curvTypestring, [p1, p2, ... pn], marker, elementsOnCurve,


distributionString, distributionVal]

In this case curvTypestring is a string with the name of the type of curve, such as “Spline”
or “Circle”. This value is used when GmshMesher writes geo-files. The second value is a list of
the point IDs that define the curve. The third value is the marker of this curve. It is used by
GmshMesher when it writes “Physical Lines” in geo-files. The fourth value, elementsOnCurve,
is an integer that says how many elements are placed along the curve. This and the following
values are None if the parameter elOnCurve in the add* method is not defined (this means
the curve is not structured). DistributionString is either “bump” or “progression” and defines
how elements are distributed on a structured curve. The last value, distributionVal, is the
number of elements along the structured curve.
Next up is the dictionary surfaces. Its values are:

[SurfaceTypeString, [c1, c2 ... cn], [[c1, c2 ... cm], ... [c1, ... ck]],
ID, marker, isStructured]

SurfaceTypeString is the name of the surface type, which can be “Plane Surface” or “Ruled
Surface”. These are the types of surface that can exist in Gmsh geo-files. Note that they
are not the same as the three types of surfaces that can be added (addStructuredSurface and
addRuledSurface both make “Ruled Surface”, but have different requirements - a structured
surface needs four structured boundary curves while ruled surface can have three or four

18
Implementation 3.2 pycalfem GeoData

curves of any type). The second and third values are lists of integer curve IDs. One is a
simple list of the curves that make the boundary, while the other is a nested list of curves
that make holes in the surface. Only plane surfaces (created with addSurface) may have
holes. Values four and five are the ID and marker numbers of the surface. The last value,
isStructured, is a boolean that GmshMesher uses to determine whether a surface is structured
or not.
Finally, the dictionary volumes looks like:

[[s1, s2 ..], [[s1,s2...],[s1,s2..],..], ID, marker, isStructured]

This is entirely analogous to the previous dictionary, surfaces, except volumes do not have
a name-value because GmshMesher only writes one type of volume (which can be structured
or not).

Methods

The functions getNewPointID, getNewCurveID, getNewSurfaceID, getNewVolumeID, and


smallestFreeKey find the a new (free) ID number if a geometric entity is added without an
ID. Note that smallestFreeKey is only called if, for example, we are adding a new curve and
curveIDspecified = True. This means that some curve has been given an ID number by the
user and we can not simply increment nextcurveID to find our next ID number, since it might
be taken. The function smallestFreeKey must thus search the curves dictionary for an unused
ID number (key).
The method checkIfProperStructuredQuadBoundary is called from inside addStructured-
Surface. It takes a list of curve IDs (integers) as parameter and finds whether the number
of elements corresponding curves are correct. There must be four curves arranged in a loop,
like a square, and the number of elements (i.e. distributionVal) on two opposite curves must
be the same.
The methods addCurve, addSurf, and addVolume are called from the adder methods.
They decrease the amount of duplicate code by handling things that must be done whenever
an entity is added, such as requesting a free ID number or making sure that the input is
correct. It is in these methods that entries are inserted into the dictionaries points, curves,
etc.
subentitiesOnEntities and subentityHolesOnEntities are helper methods for the methods
pointsOnCurves, stuffOnSurfaces and stuffOnVolumes. They get a Set of the ID numbers of
all the “sub-entities” of a set of entities. For example, all the curves on the boundaries of
a set of surfaces. The parameters are IDs, entityDict, and index. IDs is a list or set of IDs.
Parameter entityDict is a reference to one of the dictionaries that hold the geometric entities.
As mentioned, geometric entities are nested lists stored in dictionaries. The parameter index
should be the index where sub-entities are stored (for example the points of a curve).

19
3.3 pycalfem mesh Implementation

3.3 pycalfem mesh


Like the previous module pycalfem mesh contains a single class, GmshMesher. Apart from
the constructor, GmshMesher has only one method of interest to the user. That method is
create, which executes Gmsh in order to mesh the geometry.
GmshMesher writes the geometry from GeoData objects into geo-files, which is the file
format that Gmsh parses to create geometry. After Gmsh is done meshing the geometry it
writes a msh-file. This msh-file is then parsed by GmshMesher to make the mesh in the format
CALFEM for Python uses (i.e. arrays/dictionaries called coords, edof, dofs, bdofs, etc).
GmshMesher does some preprocessing of input geometry to make things easier for the user
(compared to writing geometry directly in a Gmsh geo-file). For example, by automatically
writing line loops and flipping the directions of curves so that all 2D surfaces point in the
positive z-axis. This is important because elements that point the wrong way cause faulty
FEM calculations that are difficult to diagnose.
GmshMesher has a few “hidden” attributes. They are called nodesOnCurve, nodesOnSur-
face, and nodesOnVolume. These attributes are defined when create is called (i.e. when a
mesh is created). As their names imply they are dictionaries that say which nodes are on
a given curve, surface, or volume. These attributes may change or be removed in future
versions of pycalfem mesh. There is no equivalent attribute nodeOnPoint for points.

Attributes
GmshMesher objects have a the following “public” attributes:

• geoData
A GeoData object or a path string.
• elType
Integer that defines which element type the mesh will have. Some of these are:
2 - 3-node triangle,
3 - 4-node quadrangle,
5 - 8-node hexahedron,
16 - 8-node second order quadrangle
The complete list is in the Gmsh manual, page 89.[7]
• elSizeFactor
Element sizes are multiplied by this number.
• dofsPerNode
Integer. Number of degrees of freedom per node.
• gmshExecPath
Path string to the location of gmsh.exe. Both relative and absolute paths are accepted.
If None the script will look in the PATH environment variable. (Optional)
• clcurv
If True, this tells Gmsh to try to make the mesh denser at boundaries with high
curvature. Experimental feature of Gmsh. (Optional)

20
Implementation 3.3 pycalfem mesh

• minSize
Minimum size of elements. (Optional)
• maxSize
Maximum size of elements. (Optional)
• meshingAlgorithm
String that informs Gmsh which meshing algorithm to use. ”meshadapt”, ”del2d”,
”front2d”, ”del3d”, ”front3d”, etc. (Optional)
• additionalOptions
A string with any additional command line options for Gmsh. This string is simply
added to the command that executes Gmsh. (Optional)

These are all set in the constructor.

Methods
The only method in GmshMesher that is public is

• create(is3D=False)

After GmshMesher has been initialised create can be called to mesh the geometry.
The optional parameter is3D only needs to be set in one scenario; When meshing a 3D
model and the attribute geoData is a text string instead of a GeoData object. In this case the
string should be the path to a geo-file. Normally GmshMesher can ask the GeoData object
whether it is a 2D or 3D model.
create executes Gmsh and processes the msh-file it writes. The function returns the
following values which, apart from the last one, are the same as CALFEM for Python function
trimesh2D returns.

• coords
Array of node coordinates. One row per node.
• edof
Array with element topology. One row per element.
• dofs
Array of node dofs. One row per node.
• bdofs
Boundary dofs. Dictionary containing lists of dofs for each boundary marker. Dictio-
nary key is marker number.
• elementmarkers
List of integer markers. Row i contains the marker of element i. Element markers can
be used to determine in which region an element lies.

21
3.3 pycalfem mesh Implementation

Internals

The meat of the class GmshMesher is the method create which runs Gmsh, processes its msh-
file output and returns the mesh data. What it does not do is convert geometric data in
GeoData into the geo-file that Gmsh reads. This is done by the method writeGeoFile and six
other helper methods.

Whenever the ID numbers of geometric entities are written in the geo-file, they need to be
converted. The issue is that the IDs represent indices that start at 0, while the corresponding
enumeration in the geo-file starts at 1. Curves may even be referenced by negative indices
(Curve directions are important to Gmsh, and a negative number means the curve direction is
reversed). The conversions are handled by offsetIndices(lst, offset) and formatList(lst, offset),
which increase/decrease indices and turn a list of integers into a corresponding string (such
as [2,4,5] to “2, 4, 5”), respectively.

The helper function insertInSetDict(dictionary, key, values) simply finds a set in dictionary
with the key and adds the values to it. The helper function is used in both create and
writeGeoFile.

The method writeGeoFile goes through each entity type (points, curves, surfaces, and
volumes) in the GeoData object and writes, in a geo-file, a script that will create the same
entities in Gmsh.

Surfaces are particularly difficult, and subsequently have a large portion of the code
dedicated to them, such as the helper methods writeLineLoop and makeCounterClockwise.
The big issue is that surfaces are defined by the loops of curves that are their boundary.
Gmsh requires that the direction of the curves (as defined by their start- and end-points)
go the same way along the entire loop. In geo-files the loops are written as a list of curve
IDs, and the direction may be flipped by putting a minus-sign in front of the ID-number of
the curve. The problem with this is twofold. One, this kind of complexity is contrary to
simplicity that is expected from CALFEM. Two, it is simply impossible to “flip” a curve with
a minus sign in Python because the curve can have ID= 0, and 0 = −0. The solution is to
pre-process the list of curves that define a surface so that the curves form a correct loop.
This is what writeLineLoop does. It makes the indices start at 1 instead of 0. Then it goes
through the list of curve IDs, flipping (multiplying by -1) some of them based on their start-
and end-points.

22
Implementation 3.3 pycalfem mesh

Figure 3.5: Area under a loop. The arrows point from the start point to the end
point of the lines. If a line points right (xstart < xend ) the area under the curve is
positive, otherwise negative.

All this is still not enough. If the geometry is 2D, then the curve loops must also be
counter-clockwise, or the surface normals will point in the negative z-axis. This would reverse
the node order of the elements, which in turn would ruin FEM calculations. The method
makeCounterClockwise reverses the direction of a loop if it is clockwise by multiplying the
curve IDs by −1. It determines the direction of the loop by using a simple trick.† The trick
consists of calculating the sum of the signed area under the curves of the loop. If the area is
positive then the loop is clockwise. The method only works for polygons with straight lines, so
splines are approximated with straight lines between their control points and ellipses/circles
are broken down into two straight lines as described in figure 3.6. The area under a line from
(xstart , ystart ) to (xend , yend ) is (xend − xstart ) · (yend + ystart)/2. The minus sign means that
lines that go left give positive areas, while lines that go right give negative areas. As figure
3.5 demonstrates, the summed area will be positive if the loop is clockwise.

Figure 3.6: Approximation of an ellipse segment as two straight lines ad and dc.
The points a, b, and c are know and d is calculated. Vector bd bisects the angle
abc. The length of bd is the mean of the lengths of ba and bc.

Trick found on http://stackoverflow.com/questions/1165647/

23
3.4 pycalfem vis Implementation

3.4 pycalfem vis


The module pycalfem vis contains functions that draw geometry or meshes. Unlike the visu-
alisation tools in standard CALFEM for Python, pycalfem vis does not use a class of its own
to handle drawing. Instead, it uses the graphics library visvis.
The module has a number of functions for drawing, and can draw geometry, meshes,
deformed meshes, meshes coloured by nodal values, and meshes coloured by element values.
It is also possible to add texts and labels.
The module contains no public classes, but a number of functions. After these functions
have been called in a script, it is necessary to make the script enter the application loop of
a GUI back-end. If this is not done the figures that have been plotted will disappear when
the script terminates. This can be done by adding the following at the end of the script
(assuming visvis is imported as vv):

app = vv.use()
app.Run()

This makes visvis find a GUI back-end and enter its application loop. It is also possible to
do calculations and plot while inside an application loop, as in example Mesh_Ex_09.py.

Functions
All the functions have a parameter called axes. Axes objects in visvis represent spaces wherein
drawable objects exist. Meshes and labels must be added to an Axes to be drawn. If the
parameter axes is None the current Axes will be used automatically.

• getColorbar(axes=None)

The function getColorbar returns the Colorbar object, if there is any. This lets users access
the label attribute of the Colorbar.

• addLabel(text, pos, angle=0, fontName=None, fontSize=9, color=’k’, bgcolor=None, axes=None)


• addText(text, pos, angle=0, fontName=None, fontSize=9, color=’k’, bgcolor=None, axes=None)

These functions add labels and texts to a figure/axes. Labels are placed in screen space while
Texts exist in world space. Parameter pos is the xyz-position of the addition. Texts in 2D
and Labels use 2D coordinates.
Parameter angle is the counter-clockwise rotation of the text in degrees. Parameters
fontName, fontSize, and color define the look and size of the text, while bgcolor sets the
background colour behind it. The fontName may be “mono”, “sans” or “serif”.
Colours in visvis use the same syntax as MATLAB, i.e. black is “k” and red is “r” and so
on. It is also possible to define colours as 3-tuples with RGB-values between 0 and 1. For
example, green is (0, 1, 0).

24
Implementation 3.4 pycalfem vis

• drawMesh(coords, edof, dofsPerNode, elType, axes=None, axesAdjust=True, title=”Mesh”,


color=(0,0,0), faceColor=(1,1,1), filled=False)
• drawNodalValues(nodeVals, coords, edof, dofsPerNode, elType, clim=None, axes=None,
axesAdjust=True, doDrawMesh=True, title=”Node Values”)
• drawElementValues(ev, coords, edof, dofsPerNode, elType, displacements=None, clim=None,
axes=None, axesAdjust=True, doDrawMesh=True, doDrawUndisplacedMesh=False, mag-
nfac=1.0, title=”Element Values”)
• drawDisplacements(displacements, coords, edof, dofsPerNode, elType, nodeVals=None,
clim=None, axes=None, axesAdjust=True, doDrawUndisplacedMesh=True, magnfac=1.0,
title=None)

These functions draw meshes in various ways. Most parameters are the same in these func-
tions.
Parameter coords is an array of node coordinates, each row has the xy- or xyz-coordinates
of a node. Parameter edof contains the element degrees of freedom. One row per element.
Parameters dofsPerNode and elType are the number of dofs per node and the Gmsh element
type, respectively. If axesAdjust is set to False the view will not be altered to fit the objects
added to the scene, which it does by default. Parameter title is the title label drawn at the
top of the figure.
Other parameters only exist in some of the functions. Parameters color and faceColor
define the colours of the mesh edge wire and the faces between the edges. The boolean
parameter filled decides whether faces are drawn or not. Parameter clim is a 2-tuple containing
the minimum and maximum values of the Colorbar.
If doDrawMesh is set to False the edge wire will not be drawn. Parameter ev is a a list
or array of element values. One value per element. Parameter displacements is an N-by-2 or
N-by-3 array. Row i contains the x, y, z displacements of node i.
If doDrawUndisplacedMesh is True the mesh wire of the undeformed mesh will be drawn
under the deformed mesh. Parameter magnfac is a magnification factor by which displace-
ments are multiplied. It can be used if displacements are too small to be seen.

• drawGeometry(geoData, axes=None, axesAdjust=True, drawPoints=True, labelPoints=True,


labelCurves=True, title=None, fontSize=11, N=20)

This function draws the geometry contained in the GeoData object geoData. It will not work
if GeoData is a path string. Only points and curves are drawn, not surfaces or volumes.
Most parameters are the same as in the above functions. The exceptions are drawPoints,
labelPoints and labelCurves which determine whether points and curves are drawn and labeled,
respectively.
Curves are labeled like “a(b)[c]”, where a is the curve ID, b is the number of prescribed
elements on the curve (if the curve is structured) and c is the marker of this curve. To reduce
clutter, b and c are not written out if the curve is not structured or does not have a marker.
Points are similarly labeled “a[c]”.

25
3.4 pycalfem vis Implementation

Internals

As mentioned, pycalfem vis uses the visualisation library visvis. The functions drawMesh,
drawNodalValues, drawElementValues, and drawDisplacements draw the mesh by creating a
visvis Mesh object m and putting it in the Axis. If no Axis is supplied in the parameters the
current Axis will be used or one will be created. A Mesh object represents a 3D polygonal
mesh. These four functions call the helper function preMeshDrawPrep which does various
preparations for creating the Mesh. For example, it converts the coordinates of the nodes to
3D if they are 2D. It also determines whether the mesh has three-sided or four-sided faces.
If the elements are 3D, it will also breaks these into their component faces.
Mesh objects have several attributes. Apart from vertices and faces they have attributes
that control the way the mesh is rendered, such as faceShading, edgeShading, specular, etc.† In
all the draw functions these properties are set so that the mesh is drawn without shadows or
other lighting effects. This also includes setting the Axis.light0∗ attributes ambient= 1.0 and
diffuse= 0.0. These control the level of ambient and diffuse lighting in the scene. 0 diffuse
means there are no shadows.
The function drawElementValues does not create a Mesh. Instead it uses a custom object
called elementsWobject to represent the mesh. The reason for this is that Mesh objects
are drawn with vertex colours, i.e the colours on the faces are interpolated from the colour
values of the mesh vertices/nodes. Element values need to be drawn as a single colour per
face/element, which means a custom drawing routine is required.
makeColorBar is a helper function that creates a visvis Colorbar object. Colorbars in visvis
represent the colour scale that shows the mapping between node/element values and colours.
For unknown reasons it is possible to create several overlapping Colorbars in visvis, so the
function getColorbar (which is called by makeColorBar) finds the current active one if it exists
in order to sidestep this issue.

Curves and drawGeometry

The function drawGeometry draws the points and curves of a GeoData object. To aid it, it
uses a number of helper functions called catmullspline, bspline, circleArc, and ellipseArc.
As their names imply they return curves that can be plotted.
The “splines” in Gmsh are more precisely Catmull-Rom splines. In order to draw geometry
the way it will be interpreted by Gmsh it is necessary to construct a parametric representation
of these splines. This is done in the function catmullspline, which takes a list of control points
as parameter. The function starts by creating extra control points at the start and end of
the list. This is necessary because Catmull-Rom splines are calculated with the following
formula.


The Mesh class is described at http://code.google.com/p/visvis/wiki/cls_Mesh

The Axis class is described at http://code.google.com/p/visvis/wiki/cls_Axes

26
Implementation 3.4 pycalfem vis

  
0 2 0 0 Pi−1
   −1 0 1 0   Pi
  
q(t) = 0.5 1 t t2 t3  2 −5 4 −1   Pi+1

 (3.1)
−1 3 −3 1 Pi+2

where q(t) is a parametric point [x(t), y(t), z(t)] on the curve. t is a parameter between 0 and
1. Pi is a control point and i goes from 1 to N − 2 if N is the number of control points.†
This formula creates a curve q(t) which connects control points Pi and Pi+1 . The other
two points determine the tangent of the curve at these points. The whole curve is calculated
by applying this formula to every group of four point in the list of control points.
Note that the curve starts at the second point and ends at the second-to-last point. This
means an extra set of points are needed on the ends. These two points are created by either
mirroring the second control point in the first or by duplicating the second-to-last point,
depending on whether the curve is open or closed.∗ See figure 3.7.

Figure 3.7: Creation of extra control points for Catmull-Rom splines. The example
on the left is a closed spline with four control points (P1 − P4 ), so the extra points
P0 and P5 are created by duplicating the second points at either end and appending
them to the other end. The example on the left also has four control points, but
the spline is open. In this case the extra points are created by mirroring the
second points in the first (or second-to-last mirrored in the last) and appending
the mirrored points.

The function bspline works similarly as catmullspline. It returns a uniform cubic B-spline.
This type of curve also needs an extra set of points at the ends to look like they do in Gmsh.
The extra points are determined in exactly the same way as before.
A parametric representation of the B-spline is calculated with the formula

This formula can be found at http://www.mvps.org/directx/articles/catmull/

This idea was taken from http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/
B-spline/bspline-curve-closed.html

27
3.4 pycalfem vis Implementation

  
−1 3 −3 1 Pi−1
  1  3 −6 3 0   Pi 
q(t) = s3 s2 s 1    (3.2)
6  −3 0 3 0   Pi+1 
1 4 1 0 Pi+2

where Pi is a control point and i goes from 1 to N − 2 if N is the number of control points.
s is a parameter between 0 and 1.‡
Ellipse arcs and circle arcs are calculated by the function ellipseArc. In Gmsh ellipse
arcs are defined by four points; start point, center point, end point, and a point on the
major axis of the ellipse (due to symmetry circle arcs do not need the last point). This
posed an unexpectedly large obstacle during development, because no formula for determining
arbitrary ellipse arcs from these points could be found. However, the problem could be solved
in the case of 2D axis-aligned ellipses. Therefore, ellipseArc starts by transforming these
points to a 2D axis-aligned ellipse. See figure 3.8.

Figure 3.8: The four points that define an ellipse arc are transformed to a 2D
coordinate system where the ellipse is axis aligned.

At this point we want to determine the parameters a and b (the lengths of the major and
minor axes) of the ellipse equation

x = a · cos(t) (3.3)
y = b · sin(t) (3.4)

where 0 < t < 2π. This is done with


See http://www.siggraph.org/education/materials/HyperGraph/modeling/splines/b_spline.
htm

28
Implementation 3.4 pycalfem vis

s
(ye · xs )2 − (xe · ys )2
a= (3.5)
ye2 − ys2
s
(ye · xs )2 − (xe · ys )2 x2e − x2s
b= · 2 (3.6)
ye2 − ys2 ys − ye2

where (xs , ys ) is the start point and (xe , ye ) is the end point of the ellipse segment. If
memory serves, these equations were determined by feeding the ellipse equation (and some
conditions like −π < t < π) into Wolfram Alpha and cleaning up the resulting equations.

We then determine a range for the parameter t with

y s xs
ts = atan2( , ) (3.7)
b a
ye xe
te = atan2( , ) (3.8)
b a

where ts is the value of t at the start point, and te is t for the end point. The function
atan2(x, y) gives the angle from the negative x-axis (between −pi and pi) of a vector (x, y).
However, since the limits of t is −pi and pi, we do not yet know whether the shortest“distance”
between ts and te is direct or if it crosses the discontinuity at the limit. We find out by simply
calculating the parameter distances and choosing the shortest distance. See figure 3.9.

29
3.5 Example scripts Implementation

Figure 3.9: The parameter t determines a point on an ellipse in a similar way an


angle determines a point on a circle (but not quite the same way). The shortest
distance between two points can cross the discontinuity at t = ±π like in this
example.

This gives us the range of t that makes the ellipse. We pass values t from this range to
the ellipse equation (equations (3.3) and (3.4)) which gives us vertices on the ellipse. This is
where the ellipse segment lies in this 2D coordinate system, so we transform the vertices on
the curve back to the original coordinate system.

3.5 Example scripts


A handful of example scripts were written. These demonstrate how to use the new modules.
As of writing there are ten scripts named Mesh_Ex_*.py, where * is a number between 01
and 10. These are all in the appendix. Most of the examples are fairly similar to each other
and do not have to be read in order, but the later examples are less thoroughly commented.

3.6 Other changes to CALFEM for Python


Functions planqe and planqs were added to the existing pycalfem module. These functions
calculate the stiffness matrix and element stresses/strains of quadrilateral elements. The

30
Implementation 3.6 Other changes to CALFEM for Python

function plani4e† , was also added.


Converted from CALFEM for MATLAB by Eskil Andreasson and given to me in private communication

31
Chapter 4

Performance test

In order to test the performance of the mesher modules some experiments were conducted.
The purpose was to see how fast the mesher could mesh different types of meshes and compare
performance with the older trimesh2d routine, which uses Triangle.exe to mesh.
The experiments were done with various different values for the GmshMesher parameter
elmSizeFactor, alternatively the parameter maxArea for trimesh2d().
The tables below show the number of elements in the mesh and the mean time to mesh.
Due to the long mesh times the mean values were calculated from just three repetitions.
The table columns are Elements (the number of elements), mesh time (the total meshing
time in seconds), Gmsh (seconds spent waiting on Gmsh to mesh the geometry and write a
msh-file), parse .msh (time used for parsing the textttmsh-file), and finally parse/Gmsh ratio
(A procent ratio of the two previous times).
The first three tables (4.1, 4.2, 4.3) describe unstructured meshing in 2D. By comparing
the mesh times in table 4.2 and table 4.3 we see that GmshMesher is slightly slower than
than the function trimesh2d. We can also see in table 4.2 that the amount of time spent
parsing the output of Gmsh is about the same as the time Gmsh took to mesh the geometry.
Comparing this to table 4.1 shows that meshing quadrangular elements takes more time than
meshing triangles (about 10 times longer at 1 million elements), and that most of the time
is used by Gmsh. This is not surprising since the running time of the parsing algorithm
is roughly linearly proportional to the number of elements, and thus does not change with
element type. In Gmsh quadrangles are created by merging triangles, which is apparently a
slightly time-consuming process.
The test was also done on a structured mesh. The mesh had the same shape as the
previous tests (a flat square), but the elements were distributed in a grid pattern instead of
unstructured distribution. Comparing tables 4.1 and 4.4 hints that structured meshes are
made more quickly than unstructured meshes (atleast for 2D quadrangles).
Similar tests were also done on the 3D dice-shaped geometry in Mesh_Ex_04.py. In this
case the meshed geometry was structured and had hexahedral elements. Again, the mean
time was calculated from the mean running times of three repetitions. The results are in table
4.5, which do not seem to show anything conclusive, except that meshing in 3D is slightly
slow and that the time spent on parsing the msh-files of 3D meshes is remarkably longer than

33
Performance test

2D quads unstructured (Gmsh)


Elements mesh time (s) Gmsh (s) parse .msh (s) parse/Gmsh ratio
977 0.45 0.36 0.09 25 %
2,032 0.70 0.54 0.15 28 %
4,194 1.79 1.47 0.31 21 %
8,079 2.40 1.81 0.59 33 %
16,342 5.87 4.67 1.21 26 %
33,361 16.19 13.74 2.44 18 %
66,018 31.74 26.85 4.88 18 %
132,700 82.89 73.07 9.81 13 %
266,112 308.01 288.03 19.96 7%
532,756 650.23 609.78 40.43 7%
1,064,747 1116.82 1036.29 80.48 8%

Table 4.1: Meshing times for an unstructured mesh with 2D quadrangular ele-
ments. Meshing was done by Gmsh.exe by calling create in GmshMesher.

2D triangles unstructured (Gmsh)


Elements mesh time (s) Gmsh (s) parse .msh (s) parse/Gmsh ratio
1,018 0.25 0.18 0.07 37 %
2,066 0.34 0.22 0.12 55 %
4,282 0.60 0.35 0.25 73 %
8,486 0.99 0.49 0.49 100 %
16,930 2.06 1.05 1.00 95 %
34,152 3.38 1.44 1.94 135 %
68,658 6.80 2.88 3.92 136 %
137,574 14.25 6.36 7.89 124 %
275,310 28.42 12.43 15.97 128 %
552,702 60.98 26.05 34.91 134 %
1,106,748 124.37 57.91 66.42 115 %
2,212,960 262.29 123.85 138.36 112 %
4,436,214 609.88 300.00 309.73 103 %

Table 4.2: Meshing times for an unstructured mesh with 2D triangular elements.
Meshing was done by Gmsh.exe by calling create in GmshMesher

34
Performance test

2D triangles unstructured (Triangle)


Elements mesh time (s)
1,542 0.05
3,272 0.07
6,300 0.11
1,303 0.14
2,540 0.24
5,123 0.42
10,187 0.79
20,417 1.39
40,763 2.88
81,525 5.70
162,798 11.01
325,704 23.11
651,175 44.90
1,302,622 92.24
2,604,770 183.81

Table 4.3: Meshing times for an unstructured mesh with 2D triangular elements.
Meshing was done by Triangle.exe by calling trimesh2d

for 2D meshes.

Even though the main purpose of these experiments was to test the performance of the
mesher, it was noted that the visualisation function drawMesh failed to draw meshes with
more than around 1 million faces, possibly due to memory allocation issues.

35
Performance test

2D quads structured (Gmsh)


Elements mesh time (s) Gmsh (s) parse .msh (s) parse/Gmsh ratio
1,296 0.28 0.16 0.12 73 %
2,401 0.36 0.17 0.19 113 %
4,096 0.52 0.21 0.31 149 %
6,561 0.72 0.22 0.49 223 %
10,000 1.02 0.26 0.75 286 %
14,641 1.40 0.31 1.09 348 %
20,736 1.90 0.38 1.52 398 %
28,561 2.60 0.48 2.11 444 %
38,416 3.45 0.61 2.84 469 %
50,625 4.52 0.75 3.76 501 %
65,536 5.77 0.92 4.85 528 %
83,521 7.32 1.14 6.17 542 %
104,976 9.14 1.40 7.73 553 %
130,321 11.34 1.71 9.62 563 %
160,000 13.85 2.08 11.76 566 %
194,481 16.89 2.50 14.37 575 %

Table 4.4: Meshing times for a structured mesh with 2D quadrangular elements.
Meshing was done by Gmsh.exe by calling create in GmshMesher.

3D hexahedrons structured (Gmsh)


Elements mesh time (s) Gmsh (s) parse .msh (s) parse/Gmsh ratio
1,536 0.53 0.21 0.32 154 %
3,750 1.49 0.39 1.10 284 %
7,776 3.81 0.85 2.95 347 %
14,406 8.95 1.92 7.02 365 %
24,576 19.24 4.04 15.17 375 %
39,366 40.51 9.50 30.95 326 %
60,000 72.54 15.57 56.97 366 %
87,846 127.87 28.39 99.28 350 %
124,416 214.44 46.74 167.34 358 %
171,366 357.56 82.62 274.22 332 %

Table 4.5: Meshing times for a structured mesh with 3D hexahedral elements.
Meshing was done by Gmsh.exe by calling create in GmshMesher.

36
Chapter 5

Differences between Gmsh and the


meshing modules

Geometry in Gmsh is defined in script files with the extension geo. Other properties that
influence meshing are set as parameters when running Gmsh from the command-line. The
modules pycalfem GeoData and pycalfem mesh emulate these geo-files and properties, in order
to let users access some Gmsh meshing functionality from python scripts.

5.0.1 Geometry
Gmsh reads geometry data from geo-files, which are human-readable scripts that tell Gmsh
how to construct the geometry. geo-files can be written by hand or generated by Gmsh
when a user makes geometry in its graphical user interface. geo-files are simply a series of
commands that construct geometry. The python class GeoData has methods that correspond
to a subset of these commands.
For example, to define a triangular surface between three points where one side has
marker = 5 you might write the following in a Gmsh geo-file:

Point(1) = {2, 1, 0, 0.3};


Point(2) = {3, 1, 0, 0.3};
Point(3) = {2, 2, 0, 0.3};
Line(1) = {1,2}
Line(2) = {2,3}
Line{3} = {3,1}
LineLoop(1) = {1,2,3}
Plane Surface(1) = {1}
Physical Line(5) = {2};

By comparison, with the new modules you would write (in a python script)

g = GeoData()
g.addPoint([2, 1], elSize=0.3)

37
Differences between Gmsh and the meshing modules

g.addPoint([3, 1], elSize=0.3)


g.addPoint([2, 2], elSize=0.3)
g.addSpline([0,1])
g.addSpline([1,2], marker=5)
g.addSpline([2,0])
g.addSurface([0,1,2])

GeoData is the object that receives commands and stores the geometry.
There are several differences. One of the important ones is that indices start at 1 in Gmsh
and 0 in Python. Points in Gmsh have four parameters and an ID-number. The parameters
are the x-, y-, z-positions of the point and element size at the point. In GeoData, the Point
has a different set of parameters, some of which are optional. These are position, ID, marker,
and elSize.

There are different types of curves in Gmsh. In the top example we used Line, which is
a straight line between two points. Since a spline with two points is functionally the same as
a straight line, there are no lines in GeoData. Instead splines are used. The remaining Gmsh
curve types (BSpline, Circle, Ellipse) are defined similarly in both Gmsh and GeoData.

Whereas in Gmsh markers are applied with the command Physical Line(5) = {2}, in
GeoData markers are set when the entity is added with the parameter marker.

In Gmsh it is necessary to define LineLoops. LineLoops are used for specifying the sur-
face boundary when surfaces are created. In GeoData there are no line loops. Surfaces use
lists of curves instead (the parameters outerLoop and holes of addSurface, for example).

Plane Surface in Gmsh corresponds to the method addSurface in GeoData. There is also
Ruled Surface that corresponds to addRuledSurface. GeoData has a third surface type called
addStructuredSurface which is the same as a combined Ruled Surface and Transfinite Surface.

In 2D, one very important difference is that Gmsh requires that the Line Loops that de-
fine surfaces are counter clockwise. Otherwise the surface normals of elements on the surface
will point in the negative z-direction, which will ruin calculations. Since that is bothersome
the class GmshMesher will automatically reorient surfaces so that the surface is pointing in
the correct way.
The curves can be ordered in a clockwise or counter-clockwise order. The direction of
the curves themselves (as defined by the order of the points that make the curve) does not
matter - with one exception. The only situation where the order of points in a curve matters
is when the curve is “structured” and has “progression” distribution, i.e when nodes are placed
in a geometric progression along the curve. In this situation the order of the nodes must be
reversed to reverse the direction of the progression.

Curves are made structured in different ways in Gmsh and GeoData. For example, in Gmsh
we could create a structured four-sided surface with the following script:

38
Differences between Gmsh and the meshing modules

Point(1) = {0, 0, 0, 1};


Point(2) = {1.2, 0, 0, 1};
Point(3) = {1, 1.3, 0, 1};
Point(4) = {0, 1, 0, 1};
Spline(1) = {1, 2};
Transfinite Line{1} = 11 Using Bump 0.2;
Spline(2) = {2, 3};
Transfinite Line{2} = 21 Using Progression 1.1;
Spline(3) = {3, 4};
Transfinite Line{3} = 11 Using Bump 0.2;
Spline(4) = {1, 4};
Transfinite Line{4} = 21 Using Progression 1.1;
Line Loop(1) = {1, 2, 3, -4};
Ruled Surface(1) = {1};
Transfinite Surface{1} = {1, 2, 3, 4};

In Python we would instead write:

g = GeoData()
#Add Points:
g.addPoint([0,0])
g.addPoint([1.2, 0])
g.addPoint([1, 1.3])
g.addPoint([0, 1])
#Add Splines:
g.addSpline([0,1], elOnCurve=10, elDistribType="bump", elDistribVal=0.2)
g.addSpline([1,2], elOnCurve=20, elDistribType="progression", elDistribVal=1.1)
g.addSpline([2,3], elOnCurve=10, elDistribType="bump", elDistribVal=0.2)
g.addSpline([0,3], elOnCurve=20, elDistribType="progression", elDistribVal=1.1)
#Add Surface:
g.addStructuredSurface([0,1,2,3])

Gmsh has the command Transfinite Line to make a curve structured. In GeoData a
curve is made structured by defining the parameter elOnCurve when the curve is added.
For structured surfaces Gmsh has the command Transfinite Surface, which turns a
surface into a structured surface. In GeoData there is a method called addStructuredSurface
which both creates a surface and makes it structured (The surface must have four edges).
Note that the Line Loop in the top example contains curve −4, i.e. the direction of
curve 4 is reversed to make the loop. This is not necessary in the corresponding command
addStructuredSurface due to the preprocessing mentioned above (Also remember that Python
uses 0-based indices, so the curve is 3, not 4, in Python).

39
Differences between Gmsh and the meshing modules

5.0.2 How to make quadrangular elements


In Gmsh you would add the following command to a geo-file to make all elements quad-
shaped:

Mesh.RecombineAll = 1;

In Python you set the element type when you create the GmshMesher object that handles
meshing. In the example the element type (elType) is 3, which corresponds to quads with
four nodes. If a user wants second order quads with eight nodes, they would set elType = 16.
To do the same directly in Gmsh would be slightly more complicated.

mesher = GmshMesher(geoData = g,
elType = 3,
dofsPerNode= 1)

40
Chapter 6

Conclusions

The new modules have yet to be tested in the wild, so it remains to be seen if they are
beneficial to FEM students and other users. However, it is already possible to make some
comparisons between expectations at the start of the project and the results.

One noticeable difference from the initial plan is that the new visualisation functionality
did not replace the old. In one way this is unfortunate, since it increases the size of the
library and makes the design less similar to CALFEM for MATLAB. As a learning tool it is
especially important that the library is simple and does not overwhelm the user with func-
tionality they do not need. On the other hand, having pycalfem vis separate from the rest of
the package means it does not break any existing code. It also means it is possible for a user
to to make full use of the capabilities of visvis if they want to.

The plans to convert many MATLAB functions to Python did not happen. However, the
conversion process is time-consuming and unchallenging. Therefore it is not particularly well
suited to be a major part of a degree project.

41
Chapter 7

Future Work

There is much work to be done still.

2D line elements have been completely neglected in this project in favour of 3D elements
and quads. As a result the mesh module has not been tested for that sort of element, and
it is not possible to draw line elements in the new visualisation module. This neglect should
be amended.

Many parts of CALFEM for Python assume that the mesh is in 2D or assumes triangu-
lar elements. Notably, function applyBC can only apply boundary conditions in the first two
dimensions.

There is some visualisation functionality that is still missing from the new visualisation
module. For example, it is not possible to draw isolines, element flux as arrows, or principal
stresses.
In general, very few MATLAB functions have been converted in this project. This still
needs to be done.

Gmsh entities Compound Line and Compound Surface could be implemented in classes Geo-
Data and GmshMesher. Compound Line/Surface allow several curves/surfaces to be treated
as a single curve/surface. However, it is doubtful whether the added functionality would
outweigh the issue of feature creep.

43
Chapter 8

Example Case

In this chapter we will go through an example case in depth. The figure below illustrates the
example, which consists of a thick square with a stiff shell and flexible centre. The square
has a downward force applied on the top.

Figure 8.1: The problem case.

8.1 The script


To start with, we import everything we need. In this case we use named imports because we
want to be able to see which modules we are calling.

45
8.1 The script Example Case

import pycalfem_GeoData
import pycalfem_mesh
import pycalfem_vis as pcv
import visvis as vv
from pycalfem import *
from pycalfem_utils import *

8.1.1 Defining the geometry


The next step is to define our problem geometry. In ordinary CALFEM, this would consist of
two arrays containing points and lines. Here, however, things are slightly more complicated
due to the larger variety of curves and surfaces we can make, but for this example we’ll keep
things fairly simple.
We begin by creating a GeoData object that will hold our geometry.

g = pycalfem_GeoData.GeoData()

Next, we add geometric points. The function addPoint has four parameters, but only one
is non-optional, the coordinates. We add one point for each corner of the squares in figure
8.1. One of the other parameters is ID, which is a number that identifies a point. Since we
do not specify IDs, the points will automatically receive IDs starting from 0.

g.addPoint([0, 0]) #0
g.addPoint([1, 0]) #1
g.addPoint([1, 1]) #2
g.addPoint([0, 1]) #3
g.addPoint([0.2, 0.2]) #4
g.addPoint([0.8, 0.2]) #5
g.addPoint([0.8, 0.8]) #6
g.addPoint([0.2, 0.8]) #7

We add curves that connect our points. There are several types of curves available. In
this case we use splines, which pass through all the points listed in the first parameter, which
is a list of point IDs. We also set markers for the curves that correspond to the bottom and
top of the big square. We will use these markers to apply boundary conditions. Like the
points, curves also have an ID parameter that is automatically filled in if unspecified.

g.addSpline([0, 1], marker=70) #0


g.addSpline([2, 1]) #1
g.addSpline([3, 2], marker=90) #2
g.addSpline([0, 3]) #3
g.addSpline([4, 5]) #4
g.addSpline([5, 6]) #5
g.addSpline([6, 7]) #6
g.addSpline([7, 4]) #7

46
Example Case 8.1 The script

The final part of defining 2D geometry is adding surfaces. The method addSurface has
four parameters, outerLoop, holes, ID and marker.
Here we add two surfaces. The first surface is the outer shell of the square. Its outer
boundary is defined by the curves 0, 1, 2 and 3. Its inner boundary (or “hole”) is defined by
the curves 4, 5, 6 and 7. Note that a surface may have many holes, so the parameter hole is
a list of lists, rather than a simple list.
The center square is similarly defined. Both surfaces are also given a marker. These
markers will be used for setting different material properties to elements in these regions.

g.addSurface([0,1,2,3], holes=[[4,5,6,7]], marker = 55)


g.addSurface([4,5,6,7], marker = 66)

8.1.2 Meshing the geometry


At this point we may mesh the geometry. This is done by creating a GmshMesher object
and calling its create method. GmshMesher has a large number of optional parameters that
influence the result of the meshing process. Below we define the necessary parameters. The
first parameter is geoData, which is simply the GeoData object we have made (It may also
be a string containing a file path to a Gmsh geo-file). The second parameter is the path to
the Gmsh executable file. Here, it is undefined so the program will attempt to find Gmsh
by looking in the PATH environment variable. Parameter elSizeFactor is a number that
multiplies the size of elements (size means the length of the sides of the elements). The
final parameters dofsPerNode and elType are the number of degrees of freedom per node and
element type. Element type 3 means quadrangular elements.
The method create returns a number of values that define the mesh. If you have used
trimesh2d you will be familiar with all of these except elementmarkers. The value coords
contains the node coordinates of the mesh. Meanwhile, edof, dofs and bdofs contain the
degrees of freedom by element, node, and boundary marker.

elType = 3 #Element type 3 is quad.


dofsPerNode = 2 #Degrees of freedom per node.

mesher = pycalfem_mesh.GmshMesher(geoData = g,
gmshExecPath = None,
elSizeFactor = 0.04,
elType = elType,
dofsPerNode= dofsPerNode)

coords, edof, dofs, bdofs, elementmarkers = mesher.create()

8.1.3 Solving the problem


Solving problems is done in the same way with or without the new modules from this project.
The sole difference is the existence of the aforementioned elementmarkers. However, for com-

47
8.1 The script Example Case

pleteness sake we demonstrate how to solve the problem here.


The first step is to define problem constants, such as thickness t, Poisson’s ratio v, Young’s
modulus E, and material matrix D. Since we want different material properties in the hard
shell and soft center we need two material matrices D1 and D2. We place these in a Python
dictionary which we call Ddict. The keys to the dictionary are the markers that we applied
to the two surfaces (55 and 66). This will let us access the correct material matrix of a given
element via the array elementmarkers.
We also set the problem type ptype= 1, which means this is a plane stress problem (2
means plane strain). The list ep contains the problem type and thickness, and will be used
as a parameter in the next step.

t = 0.2
v = 0.35
E1 = 2e9
E2 = 0.2e9
ptype = 1
ep = [ptype, t]
D1 = hooke(ptype, E1, v)
D2 = hooke(ptype, E2, v)
Ddict = {55 : D1, 66 : D2}

The second step consists of assembling the stiffness matrix K. First, we get the total
number of degrees of freedom, nDofs, from the size of the array dofs and initialise an empty
matrix K. We also extract the x- and y-coordinates of the nodes in each element by calling
the coordxtr function.
Next, we iterate over each element and add the element stiffness matrixKe to K. Each
row of edof, ex, ey, and elementmarkers correspond to the dofs, x-coordinates, y-coordinates,
and element markers of an element. These are passed to the function planqe, which returns
the element stiffness matrix Ke of a quadrangular solid element. Ke is added to K by the
function assem.

nDofs = size(dofs)
K = zeros([nDofs,nDofs])
ex, ey = coordxtr(edof, coords, dofs)
for eltopo, elx, ely, elMarker in zip(edof, ex, ey, elementmarkers):
Ke = planqe(elx, ely, ep, Ddict[elMarker])
assem(eltopo, K, Ke)

We prepare boundary conditions by calling the function applybc. The variable bc is an


array containing prescribed dofs, while bcVal contains the prescribed values. These are used
later.
The function applybc also takes parameter bdofs, which is a dictionary of which dofs belong
to which boundary marker. The value 70 is the marker of the boundary we want to apply
the boundary condition to. 0.0 is the value we apply. The function also has a parameter

48
Example Case 8.1 The script

dimension that determines in which direction the boundary condition is applied. The default
value is 0, which means “in all dimensions” (1 means x, 2 means y).
The boundary condition we apply here locks the bottom of the square in place.

bc = array([],’i’)
bcVal = array([],’i’)
bc, bcVal = applybc(bdofs,bc,bcVal, 70, 0.0)

The force on top of the square is applied with the following commands. First, we initialise
an empty force array. Then, we call applyforce to apply the force −106 in the y-direction to
all nodes with marker= 90.

f = zeros([nDofs,1])
applyforce(bdofs, f, 90, value = -10e5, dimension=2)

We get the solution to the problem by calling solveq. The first return value a is an array
containing the displacement of every dof. The second return value r contains the reaction
forces.

a,r = solveq(K,f,bc,bcVal)

We want to measure the effective stress in the deformed object. This can be done in
a number of ways. Here, we begin by extracting the element displacements by calling ex-
tractEldisp. We also initialise an empty list vonMises, which will hold the effective stress of
each element.
In the for-loop we calculate stresses es in the quadrilateral elements with the planqs
function. The list es contains normal stresses σx andpσy , and shear stress τxy . These values
are inserted into the von Mises stress equation σv = σx2 − σx σy + σy2 + 3τxy
2 , which gives us

an effective stress value.

ed = extractEldisp(edof,a)
vonMises = []
for i in range(edof.shape[0]):
es, et = planqs(ex[i,:], ey[i,:], ep, Ddict[elementmarkers[i]], ed[i,:])
vonMises.append( math.sqrt( pow(es[0],2) - es[0]*es[1] + pow(es[1],2) +
3*pow(es[2],2) ) )

8.1.4 Visualising the results


We start by drawing the geometry. The function drawGeometry belongs to the pycalfem vis
module, which we imported as pcv. The function has many parameters, but the only necessary
one is the first one, which is a GeoData object that holds the geometry to be drawn.

pcv.drawGeometry(g, title="Geometry")

49
8.1 The script Example Case

Figure 8.2: The geometry.

Next, we draw the mesh. We want this to be drawn in a new window, so we call figure
from the visvis library (which we imported as vv).
The function drawMesh draws the mesh. The parameter coords and edof are the coordi-
nates and element dofs. Reminder: We got these values when we meshed the geometry. The
other two parameters were defined right before that.

vv.figure()
pcv.drawMesh(coords=coords, edof=edof, dofsPerNode=dofsPerNode,
elType=elType, filled=True, title="Mesh")

We also draw the deformed mesh, i.e. the solution to the problem we solved. This is
done by calling drawDisplacements. The first parameter is the displacement solution a. The
parameter doDrawUndisplacedMesh determines whether the undeformed mesh will be drawn
superimposed on the deformed mesh.

vv.figure()
pcv.drawDisplacements(a, coords, edof, dofsPerNode, elType,
doDrawUndisplacedMesh=False, title="Displacements")

Next, we draw the von Mises effective stresses of the elements by calling drawElementVal-
ues. Like the other visualisation functions this one has many parameters. The first one is a
list (or array) of scalar element values. the variable a belongs to the parameter displacements

50
Example Case 8.1 The script

Figure 8.3: The mesh.

Figure 8.4: The deformed mesh.

51
8.1 The script Example Case

which (as the name implies) contains the displacements of the dofs. The boolean parameters
doDrawMesh determines whether the black borders around elements are drawn.
The function getColorbar gets the visvis Colorbar object that can be seen on the right of
figure 8.5. We use the reference to this object to set its text label to “Effective stress”.

vv.figure()
pcv.drawElementValues(vonMises, coords, edof, dofsPerNode, elmType, a,
doDrawMesh=True, doDrawUndisplacedMesh=False,
title="Effective Stress")
pcv.getColorbar().SetLabel("Effective stress")

Figure 8.5: The deformed mesh with von Mises effective stress.

Finally, we start the application loop of the graphical user interface that houses our figures.
If we did not do this step, the figures would disappear when the script terminates. The visvis
function use automatically gets a Python GUI backend (such as wxPython or PyQt if they
exist on the computer), and Run enters its main loop. See Mesh_Ex_09.py for an example
on how to embed visvis figures in a GUI.

app = vv.use()
app.Run()

52
References

[1] Matti Ristinmaa, Göran Sandberg, and Karl-Gunnar Olsson, http: // science.
uniserve. edu. au/ pubs/ callab/ vol5/ ristin. html , Retrieved on 2 Feb 2013

[2] Andreas Ottosson, Implementation of CALFEM for Python, Wallin & Dalholm Digital
AB, Lund, Sweden, August, 2010

[3] Jonathan Richard Shewchuk, https: // www. cs. cmu. edu/ ~quake/ triangle. html ,
Retrieved on 25 Dec 2012

[4] C. Geuzaine and J.-F. Remacle, Gmsh: a three-dimensional finite element mesh gener-
ator with built-in pre- and post-processing facilities, International Journal for Numerical
Methods in Engineering 79(11), pp. 1309-1331, 2009

[5] http: // code. google. com/ p/ visvis/ , Retrieved on 25 Dec 2012

[6] Robert Schneiders, http: // www. robertschneiders. de/ meshgeneration/


software. html

[7] C. Geuzaine and J.-F. Remacle Gmsh Reference Manual, 19 June 2012

53
Appendix A

Examples

A.1 Mesh Ex 01.py

Figure A.1: Geometry of example 01

55
A.1 Mesh Ex 01.py Examples

Figure A.2: Mesh of example 01

’ ’ ’ Example 01
Shows how t o c r e a t e s i m p l e g e o m e t r y from s p l i n e s and e l l i p s e
a r c s , and how t o mesh a quad mesh i n GmshMesher .
A l s o d e m o n s t r a t e s drawGeometry ( ) , drawMesh , and d r a w i n g t e x t s
and l a b e l s i n a f i g u r e .
’’’

from p y c a l f e m G e o D a t a import ∗
from p y c a l f e m m e s h import ∗
import p y c a l f e m v i s a s pcv
import v i s v i s a s vv

#DEFINE GEOMETRY:
g = GeoData ( ) #C r e a t e a GeoData o b j e c t t h a t h o l d s t h e g e o m e t r y .

#Add p o i n t s :
# The f i r s t p a r a m e t e r i s t h e c o o r d i n a t e s . These can be i n 2D o r
3D .
# The o t h e r p a r a m e t e r s a r e n o t d e f i n e d i n t h i s e x a m p l e . These
parameters are
# ID , marker , and e l S i z e .
# S i n c e we do n o t s p e c i f y an ID t h e p o i n t s a r e a u t o m a t i c a l l y
a s s i g n e d IDs , s t a r t i n g from 0 .
g . addPoint ( [ 0 , 0 ] )
g . addPoint ( [ 2 , 0 ] )
g . addPoint ( [ 2 , 1 ] )
g . addPoint ( [ 0 , 1 ] )
g . addPoint ( [ 0 . 5 , 0 . 3 ] )
g . addPoint ( [ 0 . 3 , 0 . 7 ] )

56
Examples A.1 Mesh Ex 01.py

g . addPoint ( [ 0 . 7 , 0.7])
g . addPoint ( [ 0 . 8 , 0.5])
g . addPoint ( [ 1 . 7 , 0.5])
g . addPoint ( [ 1 . 5 , 0.5])
g . addPoint ( [ 1 . 7 , 0.7])

#Add c u r v e s :
# There a r e f o u r t y p e s o f c u r v e s . I n t h i s e x a m p l e we c r e a t e an
e l l i p s e a r c and some s p l i n e s .
# The f i r s t p a r a m e t e r i s a l i s t o f p o i n t I D s t h a t d e f i n e t h e
curve .
# C u r v e s can ha ve h ave I D s and m a r k e r s . I n t h i s e x a m p l e t h e I D s
are u n d e f i n e d so the c u r v e s are
# a u t o m a t i c a l l y a s s i g n e d I D s . The m a r k e r s can be u s e d f o r
i d e n t i f y i n g r e g i o n s / boundaries in the
# model .
g . a d d E l l i p s e ( [ 7 , 8 , 9 , 1 0 ] , m a r k e r =50) #0 An e l l i p s e a r c . Read
t h e f u n c t i o n doc f o r more i n f o r m a t i o n . The f o u r p o i n t s a r e [
s t a r t , c e n t e r , m a j o r A x i s , end ]
g . a d d S p l i n e ( [ 0 , 1 ] , m a r k e r =80) #1 A s p l i n e . S p l i n e s p a s s
through the p o i n t s in the f i r s t parameter .
g . addSpline ([2 , 1]) #2
g . addSpline ([3 , 2]) #3
g . addSpline ([0 , 3]) #4
g . a d d S p l i n e ( [ 7 , 9 ] , m a r k e r =50) #5
g . addSpline ([10 , 9]) #6
g . addSpline ([4 , 5 , 6 , 4]) #7 T h i s i s a c l o s e d s p l i n e
. The s t a r t and end p o i n t s a r e t h e same ( 4 ) .

#Add a s u r f a c e :
# S u r f a c e s a r e d e f i n e d by i t s c u r v e b o u n d a r i e s .
# The f i r s t p a r a m e t e r i s a l i s t o f c u r v e I D s t h a t s p e c i f y t h e
o u t e r boundary of the s u r f a c e .
# The s e c o n d p a r a m e t e r i s a l i s t o f l i s t s o f c u r v e I D s t h a t
s p e c i f y holes in the s u r f a c e .
# I n t h i s e x a m p l e t h e r e a r e two h o l e s .
# The b o u n d a r i e s and h o l e s must be c l o s e d p a t h s . We can s e e t h a t
[ 7 ] i s closed because curve 7
# is a closed spline .
# a d d S u r f a c e c r e a t e s a f l a t s u r f a c e , s o a l l c u r v e s must l i e on
t h e same p l a n e .
g . addSurface ([4 ,3 ,2 ,1] , [ [ 7 ] , [ 5 , 6 , 0 ] ] )

#MESHING :
e l T y p e = 3 #E le m e n t t y p e 3 i s quad . ( 2 i s t r i a n g l e . See u s e r
manual f o r more e l e m e n t t y p e s )
d o f s P e r N o d e= 1 #D e g r e e s o f f r e e d o m p e r node .

57
A.1 Mesh Ex 01.py Examples

mesher = GmshMesher ( geoData = g ,


gmshExecPath = None , #Path t o gmsh . e x e . I f
None t h e n t h e s y s t e m PATH v a r i a b l e i s
q u e r i e d . Both r e l a t i v e and a b s o l u t e p a t h s
work , l i k e ”gmsh\gmsh . e x e ”.
e l S i z e F a c t o r = 0 . 0 5 , #F a c t o r t h a t c h a n g e s
element s i z e s .
elType = elType ,
d o f s P e r N o d e= d o f s P e r N o d e )

#Mesh t h e g e o m e t r y :
# The f i r s t f o u r r e t u r n v a l u e s a r e t h e same a s t h o s e t h a t
trimesh2d () returns .
# c o o r d s i s a s l i s t o f node c o o r d i n a t e s .
# edof i s the element topology ( element d e g r e e s of freedom )
# d o f s i s a l i s t s of a l l d e g r e e s of freedom
# bdofs i s a d i c t i o n a r y of boundary d o f s ( d o f s of geometric
e n t i t i e s with markers ) .
# e l e m e n t m a r k e r s i s a l i s t o f m a r k e r s , and i s u s e d f o r f i n d i n g
the marker o f a g i v e n element ( i n d e x ) .
c o o r d s , e d o f , d o f s , b d o f s , e l e m e n t m a r k e r s = mesher . c r e a t e ( )

#VISUALISATION :

#Hold l e f t mouse b u t t o n t o pan .


#Hold r i g h t mouse b u t t o n t o zoom .
pcv . drawGeometry ( g )#Draws t h e g e o m e t r y . Note t h a t s u r f a c e s and
v o l u m e s a r e n o t drawn a t a l l by t h i s f u n c t i o n .

vv . f i g u r e ( ) #New f i g u r e window

pcv . drawMesh ( c o o r d s=c o o r d s , e d o f=e d o f , d o f s P e r N o d e=do f s Pe r N o d e ,


e l T y p e=e l T y p e , f i l l e d =True , t i t l e =”Example 01 ”) #Draws t h e
mesh .

pcv . addText ( ”T h i s i s a Text ” , p o s =(1 , −0.3) , a n g l e =45) #Adds a


t ext in world space

o u r L a b e l = pcv . a d d L a b e l ( ”T h i s i s a L a b e l ” , p o s =(100 ,200) , a n g l e


=−45) #Adds a l a b e l i n t h e s c r e e n s p a c e
o u r L a b e l . t e x t = ”L a b e l , changed . ” #We can ch ang e t h e a t t r i b u t e s
o f l a b e l s and t e x t s , s u c h a s c o l o r , t e x t , and p o s i t i o n .
o u r L a b e l . t e x t C o l o r = ’ r ’ #Make i t r e d . ( 1 , 0 , 0 ) would a l s o hav e
worked .
ourLabel . p o s i t i o n = (20 ,30)

# E n t e r main l o o p :

58
Examples A.2 Mesh Ex 02.py

app = vv . u s e ( )
app . C r e a t e ( )
app . Run ( )

A.2 Mesh Ex 02.py

Figure A.3: Geometry of example 02

Figure A.4: Mesh of example 02

’ ’ ’ Example 02
C r e a t i n g g e o m e t r y from B−S p l i n e s and c i r c l e a r c s .

59
A.2 Mesh Ex 02.py Examples

A l s o shows how t o s e t ID numbers f o r g e o m e t r y e n t i t i e s and how


to s p e c i f y element d e n s i t y .
’’’

from p y c a l f e m G e o D a t a import ∗
from p y c a l f e m m e s h import ∗
import p y c a l f e m v i s a s pcv
import v i s v i s a s vv

#DEFINE GEOMETRY:
g = GeoData ( )

#Add p o i n t s :
#I n t h i s e x a m p l e we s e t t h e I D s m a n u a l l y .
g . a d d P o i n t ( [ −2, 0 ] , ID =0)
g . a d d P o i n t ( [ 0 , 1 ] , ID =1, e l S i z e =5) #e l S i z e d e t e r m i n e s t h e
s i z e of the elements near t h i s point .
g . a d d P o i n t ( [ 1 , 0 ] , 2 , e l S i z e =5) # e l S i z e i s 1 by d e f a u l t .
L a r g e r number means l e s s d e n s e mesh .
g . a d d P o i n t ( [ 0 , −2] , 3 ) # S i z e means t h e l e n g t h o f
the s i d e s of the elements .
g . a d d P o i n t ( [ 0 , 0 ] , 4 , e l S i z e =5)
g . addPoint ( [ . 5 , . 2 ] , 5)
g . addPoint ([ −.5 , . 5 ] , 6)
g . addPoint ([ −.7 , −.5] , 7)
#Add c u r v e s :
g . a d d C i r c l e ( [ 1 , 4 , 2 ] , 2 ) #The 3 p o i n t s t h a t d e f i n e t h e c i r c l e
a r c a r e [ s t a r t , c e n t e r , end ] . The a r c must be s m a l l e r t h a n P i
.
g . addBSpline ( [ 5 , 6 , 7 , 5 ] , 5) # B S p l i n e s are s i m i l a r to S p l i n e s ,
b u t do n o t n e c e s s a r i l y p a s s t h r o u g h t h e c o n t r o l p o i n t s .
g . addBSpline ( [ 1 , 0 , 3 , 2 ] , 4)
#Add s u r f a c e :
g . addSurface ( [ 4 , 2 ] , [ [ 5 ] ] )

#M a r k e r s do n o t hav e t o be s e t when t h e c u r v e i s c r e a t e d . I t can


be done a f t e r w a r d s .
# S e t m a r k e r =80 f o r c u r v e s 2 and 4 :
for curveID in [2 , 4 ] :
g . setCurveMarker ( curveID , 80)

#MESHING :
e l T y p e = 2 #E le m e n t t y p e 2 i s t r i a n g l e . ( 3 i s quad . See u s e r
manual f o r more e l e m e n t t y p e s )
d o f s P e r N o d e= 2 #D e g r e e s o f f r e e d o m p e r node .

mesher = GmshMesher ( geoData = g ,

60
Examples A.2 Mesh Ex 02.py

gmshExecPath = None , #Path t o gmsh . e x e . I f


None t h e n t h e s y s t e m PATH v a r i a b l e i s
q u e r i e d . R e l a t i v e and a b s o l u t e p a t h s work
.
e l S i z e F a c t o r = 0 . 0 5 , #F a c t o r t h a t c h a n g e s
element s i z e s .
elType = elType ,
d o f s P e r N o d e= d o f s P e r N o d e )

#Mesh t h e g e o m e t r y :
# The f i r s t f o u r r e t u r n v a l u e s a r e t h e same a s t h o s e t h a t
trimesh2d () returns .
# v a l u e e l e m e n t m a r k e r s i s a l i s t o f m a r k e r s , and i s u s e d f o r
f i n d i n g the marker o f a g i v e n element ( i n d e x ) .
c o o r d s , e d o f , d o f s , b d o f s , e l e m e n t m a r k e r s = mesher . c r e a t e ( )

#VISUALISATION :
#Hold l e f t mouse b u t t o n t o pan .
#Hold r i g h t mouse b u t t o n t o zoom .
pcv . drawGeometry ( g , l a b e l C u r v e s=True )#Draws t h e g e o m e t r y .

vv . f i g u r e ( ) #New f i g u r e window

pcv . drawMesh ( c o o r d s=c o o r d s , e d o f=e d o f , d o f s P e r N o d e=do f s Pe r N o d e ,


e l T y p e=e l T y p e , f i l l e d =True , t i t l e =”Example 02 ”) #Draws t h e
mesh .

vv . gca ( ) . a x i s . s h o w G r i d = True #Show g r i d

# E n t e r main l o o p :
app = vv . u s e ( )
app . C r e a t e ( )
app . Run ( )

61
A.3 Mesh Ex 03.py Examples

A.3 Mesh Ex 03.py

Figure A.5: Geometry of example 03

Figure A.6: Mesh of example 03

’ ’ ’ Example 03
Shows s t r u c t u r e d m e s h i n g i n 2D .
’’’

from p y c a l f e m G e o D a t a import ∗
from p y c a l f e m m e s h import ∗
import p y c a l f e m v i s a s pcv
import v i s v i s a s vv

62
Examples A.3 Mesh Ex 03.py

#DEFINE GEOMETRY:
g = GeoData ( )

#Add P o i n t s :
g . addPoint ( [ 0 , 0 ] )
g . addPoint ( [ 1 . 2 , 0 ] )
g . addPoint ( [ 1 , 1 . 3 ] )
g . addPoint ( [ 0 , 1 ] )
g . addPoint ( [ 2 , 0 . 5 ] )

#Add S p l i n e s :
#The f i r s t f o u r c u r v e s a r e s t r u c t u r e d c u r v e s , i . e t h e number o f
n o d e s a l o n g t h e c u r v e s i s pre −d e t e r m i n e d .
#P a r a m e t e r e l O n C u r v e s t a t e s how many e l e m e n t s a r e p l a c e d a l o n g
the curve .
#P a r a m e t e r s e l D i s t r i b T y p e and e l D i s t r i b V a l a r e o p t i o n a l
p a r a m e t e r s t h a t s p e c i f y how e l e m e n t s a r e d i s t r i b u t e d .
# ”bump ” means e l e m e n t s a r e bunched up a t t h e e n d s o r t h e
middle of the curve .
# In t h i s case e l D i s t r i b V a l i s s m a l l e r than 1 , so elements
crowd a t t h e e d g e s .
# ” p r o g r e s s i o n ” means e a c h e l e m e n t a l o n g t h e c u r v e i s l a r g e r /
s m a l l e r t h a n t h e p r e v i o u s one .
# A l a r g e r e l D i s t r i b V a l makes t h e e l e m e n t s l a r g e r a t t h e
end o f t h e c u r v e s .
g . a d d S p l i n e ( [ 0 , 1 ] , e l O n C u r v e =10 , e l D i s t r i b T y p e=”bump ” ,
e l D i s t r i b V a l =0.2)
g . a d d S p l i n e ( [ 1 , 2 ] , e l O n C u r v e =20 , e l D i s t r i b T y p e=” p r o g r e s s i o n ” ,
e l D i s t r i b V a l =1.1)
g . a d d S p l i n e ( [ 2 , 3 ] , e l O n C u r v e =10 , e l D i s t r i b T y p e=”bump ” ,
e l D i s t r i b V a l =0.2)
g . a d d S p l i n e ( [ 0 , 3 ] , e l O n C u r v e =20 , e l D i s t r i b T y p e=” p r o g r e s s i o n ” ,
e l D i s t r i b V a l =1.1) #Change o r d e r o f p o i n t s t o r e v e r s e
progression distribution
g . addSpline ([2 , 4 , 1])

#Add S u r f a c e s :
#A s t r u c t u r e d s u r f a c e must c o n t a i n 4 c u r v e s t h a t hav e t h e
parameter ’ elOnCurve ’ d e f i n e d .
#The number o f e l e m e n t s on two o p p o s i t e c u r v e s must be t h e same
( I n t h i s c a s e , c u r v e s 0 & 2 and 1 & 3 ) .
g . addStructuredSurface ([0 ,1 ,2 ,3])
g . addSurface ( [ 4 , 1 ] )

#MESHING :
e l T y p e = 3 #E le m e n t t y p e 3 i s quad . ( 2 i s t r i a n g l e . See u s e r
manual f o r more e l e m e n t t y p e s )

63
A.4 Mesh Ex 04.py Examples

d o f s P e r N o d e= 1 #D e g r e e s o f f r e e d o m p e r node .

mesher = GmshMesher ( geoData = g ,


gmshExecPath = None , #Path t o gmsh . e x e . I f
None t h e n t h e s y s t e m PATH v a r i a b l e i s
q u e r i e d . Both r e l a t i v e and a b s o l u t e p a t h s
work .
e l S i z e F a c t o r = 0 . 0 5 , #F a c t o r t h a t c h a n g e s
element s i z e s .
elType = elType ,
d o f s P e r N o d e= d o f s P e r N o d e )

#Mesh t h e g e o m e t r y :
c o o r d s , e d o f , d o f s , b d o f s , e l e m e n t m a r k e r s = mesher . c r e a t e ( )

#VISUALISATION :
pcv . drawGeometry ( g )#Draws t h e g e o m e t r y .
vv . f i g u r e ( ) #New f i g u r e window
pcv . drawMesh ( c o o r d s=c o o r d s , e d o f=e d o f , d o f s P e r N o d e=do f s Pe r N o d e ,
e l T y p e=e l T y p e , f i l l e d =True ) #Draws t h e mesh .
# E n t e r main l o o p :
app = vv . u s e ( )
app . C r e a t e ( )
app . Run ( )

A.4 Mesh Ex 04.py

Figure A.7: Geometry of example 04

64
Examples A.4 Mesh Ex 04.py

Figure A.8: Mesh of example 04

’ ’ ’ Example 0 4 .
S t r u c t u r e d 3D m e s h i n g . Adding t e x t s and l a b e l s t o f i g u r e s .
Altering axis properties .
’’’

from p y c a l f e m G e o D a t a import ∗
from p y c a l f e m m e s h import ∗
import p y c a l f e m v i s a s pcv
import v i s v i s a s vv

g = GeoData ( )

#Add P o i n t s :
g . a d d P o i n t ( [ 0 , 0 , 0 ] , ID =0)
g . a d d P o i n t ( [ 0 . 5 , −0.3 , − 0 . 3 ] , 1 )
g . addPoint ( [ 1 , 0 , 0 ] , 2)
g . addPoint ( [ 1 , 1 , 0 ] , 3)
g . a d d P o i n t ( [ 0 , 1 , 0 ] , 4 , m a r k e r = 1 1 ) #S e t some m a r k e r s no
reason .
g . a d d P o i n t ( [ 0 , 0 , 1 ] , 5 , m a r k e r = 1 1 ) #( m a r k e r s can be g i v e n t o
p o i n t s a s w e l l a s c u r v e s and s u r f a c e s )
g . addPoint ( [ 1 , 0 , 1 ] , 6 , marker = 11)
g . addPoint ( [ 1 , 1 , 1 ] , 7)
g . addPoint ( [ 0 , 1 , 1 ] , 8)

#Add s p l i n e s :
g . a d d S p l i n e ( [ 0 , 1 , 2 ] , 0 , marker = 33 , elOnCurve = 5)
g . a d d S p l i n e ( [ 2 , 3 ] , 1 , marker = 23 , elOnCurve = 5)
g . a d d S p l i n e ( [ 3 , 4 ] , 2 , marker = 23 , elOnCurve = 5)

65
A.4 Mesh Ex 04.py Examples

g . addSpline ([4 , 0] , 3 , elOnCurve = 5)


g . addSpline ([0 , 5] , 4 , elOnCurve = 5)
g . addSpline ([2 , 6] , 5 , elOnCurve = 5)
g . addSpline ([3 , 7] , 6 , elOnCurve = 5)
g . addSpline ([4 , 8] , 7 , elOnCurve = 5)
g . addSpline ([5 , 6] , 8 , elOnCurve = 5)
g . addSpline ([6 , 7] , 9 , elOnCurve = 5)
g . addSpline ([7 , 8] , 10 , elOnCurve = 5)
g . addSpline ([8 , 5] , 11 , elOnCurve = 5)

#Add s u r f a c e s :
g . addStructuredSurface ([0 , 1, 2 , 3 ] , 0 , m a r k e r =45)
g . addStructuredSurface ([8 , 9, 10 , 1 1 ] , 1)
g . addStructuredSurface ([0 , 4, 8 , 5 ] , 2 , m a r k e r =55)
g . addStructuredSurface ([1 , 5, 9 , 6 ] , 3 , m a r k e r =55)
g . addStructuredSurface ([2 , 6, 10 , 7 ] , 4)
g . addStructuredSurface ([3 , 4, 11 , 7 ] , 5)

#Add Volume :
#a d d S t r u c t u r e d V o l u m e ( ) t a k e s t h r e e a r g s . The f i r s t i s a l i s t o f
s u r f a c e IDs ( s t r u c t u r e d s u r f a c e s ) .
# The s u r f a c e s s h o u l d make a h e x a h e d r o n ( i . e . 6 s u r f a c e s ) . O t h er
k i n d s of s t r u c t u r e d volumes than hexahedra w i l l
# n o t work f o r h e x a h e d r a l e l e m e n t s , w h ic h i s t h e o n l y t y p e o f 3D
e l e m e n t t h a t CALFEM h a n d l e s .
#The two o p t i o n a l p a r a m e t e r s a r e t h e volume ID and volume m a r k e r
.
g . a d d S t r u c t u r e d V o l u m e ( [ 0 , 1 , 2 , 3 , 4 , 5 ] , 0 , m a r k e r =90)

e l T y p e = 5 #E le m e n t t y p e 5 i s h e x a h e d r o n . ( See u s e r manual f o r
more e l e m e n t t y p e s )
d o f s P e r N o d e= 1 #D e g r e e s o f f r e e d o m p e r node .

mesher = GmshMesher ( geoData = g ,


gmshExecPath = None ,
elType = elType ,
d o f s P e r N o d e= d o f s P e r N o d e )

#Mesh t h e g e o m e t r y :
coords , edof , dofs , bdofs , = mesher . c r e a t e ( )

#Hold L e f t Mouse b u t t o n t o r o t a t e .
#Hold r i g h t mouse b u t t o n t o zoom .
#Hold SHIFT and l e f t mouse b u t t o n t o pan .
#Hold SHIFT and r i g h t mouse b u t t o n t o c han g e t h e f i e l d o f v i e w .
#Hold C t r l and l e f t mouse b u t t o n t o r o l l t h e camera .
pcv . drawGeometry ( g , d r a w P o i n t s=F a l s e )#Draws t h e g e o m e t r y .

66
Examples A.5 Mesh Ex 05.py

vv . f i g u r e ( )
pcv . drawMesh ( c o o r d s=c o o r d s , e d o f=e d o f , d o f s P e r N o d e=do f s Pe r N o d e ,
e l T y p e=e l T y p e , f i l l e d =True ) #Draws t h e mesh .

pcv . addText ( ”T h i s i s a Text ” , p o s =(1 , 0 . 5 , 0 . 5 ) , a n g l e =45) #


Adds a t e x t i n w o r l d s p a c e
o u r L a b e l = pcv . a d d L a b e l ( ”T h i s i s a L a b e l ” , p o s =(20 ,30) , a n g l e
=−45) #Adds a l a b e l i n t h e s c r e e n s p a c e
o u r L a b e l . t e x t = ”L a b e l , changed . ” #We can ch ang e t h e a t t r i b u t e s
o f l a b e l s and t e x t s , s u c h a s c o l o r and p o s i t i o n .
o u r L a b e l . t e x t C o l o r = ’ r ’ #Make i t r e d . ( 1 , 0 , 0 ) would a l s o hav e
worked .

vv . gca ( ) . a x i s . showBox = 0 #Matlab s t y l e a x e s ( t h r e e a x e s i n t h e


b a c k g r o u n d i n s t e a d o f a cube )
vv . gca ( ) . S e t L i m i t s ( rangeX =(0 ,2) , rangeY =( −1 ,1.5) , r a n g e Z
=( −0.5 ,2) , m a r g i n =0.02) #Change t h e l i m i t s o f t h e a x e s .

# E n t e r main l o o p :
app = vv . u s e ( )
app . C r e a t e ( )
app . Run ( )

A.5 Mesh Ex 05.py

Figure A.9: Geometry of example 05

’ ’ ’ Example 05

67
A.5 Mesh Ex 05.py Examples

T h i s e x a m p l e shows how t o make an u n s t r u c t u r e d 3D mesh (


t e t r a h e d r o n e l e m e n t s , w h ic h c a l f e m c a n t a c t u a l l y u s e ) .
I t a l s o d e m o n s t r a t e s how t o do s u b p l o t s and c r e a t e two a x e s t h a t
a r e v i e w e d from t h e same camera .
’’’

from p y c a l f e m G e o D a t a import ∗
from p y c a l f e m m e s h import ∗
import p y c a l f e m v i s a s pcv
import v i s v i s a s vv

g = GeoData ( )

g . addPoint ( [ 0 , 0 , 0] , 0)
g . addPoint ( [ 1 , 0 , 0] , 1)
g . addPoint ( [ 0 , 1 , 0] , 2)
g . addPoint ( [ 0 , 1 , 1] , 3 , e l S i z e =0.1)
g . a d d P o i n t ( [ 0 . 5 , −0.3 , 0 ] , 4 )
g . addPoint ([ −0.3 , 0 . 5 , 0 ] , 5)
g . addPoint ( [ 0 . 7 5 , 0.75 , 0 ] , 6 )

g . addSpline ([0 ,4 ,1])


g . addSpline ([1 ,6 ,2])
g . addSpline ([2 ,5 ,0])
g . addSpline ([0 ,3])
g . addSpline ([3 ,2])
g . addSpline ([3 ,1])

g . addRuledSurface ([0 ,1 ,2])


g . addRuledSurface ([0 ,5 ,3])
g . addRuledSurface ([1 ,5 ,4])
g . addRuledSurface ([2 ,3 ,4])

g . addVolume ( [ 0 , 1 , 2 , 3 ] )

e l T y p e = 4 #E le m e n t t y p e 4 i s t e t r a h e d r o n . ( See u s e r manual f o r
more e l e m e n t t y p e s ) .
d o f s P e r N o d e= 1 #D e g r e e s o f f r e e d o m p e r node .

mesher = GmshMesher ( geoData = g ,


gmshExecPath = None ,
elType = elType ,
elSizeFactor = 0.3 ,
d o f s P e r N o d e= d o f s P e r N o d e )

#Mesh t h e g e o m e t r y :
c o o r d s , e d o f , d o f s , b d o f s , e l e m e n t m a r k e r s = mesher . c r e a t e ( )

68
Examples A.6 Mesh Ex 06.py

#VISUALISATION :

#C r e a t e two a x e s t h a t a r e v i e w e d from t h e same camera :


vv . f i g u r e ( )
a1 = vv . s u b p l o t ( 1 2 1 )
a2 = vv . s u b p l o t ( 1 2 2 )
cam = vv . c a m e r a s . ThreeDCamera ( )
a1 . camera = a2 . camera = cam
#Draw :
pcv . drawGeometry ( g , a x e s=a1 )#Draws t h e g e o m e t r y .
pcv . drawMesh ( c o o r d s=c o o r d s , e d o f=e d o f , d o f s P e r N o d e=do f s Pe r N o d e ,
e l T y p e=e l T y p e , f i l l e d =F a l s e , a x e s=a2 ) #Draws t h e mesh .

# E n t e r main l o o p :
app = vv . u s e ( )
app . C r e a t e ( )
app . Run ( )

A.6 Mesh Ex 06.py

Figure A.10: Geometry of example 06

69
A.6 Mesh Ex 06.py Examples

Figure A.11: Element values (effective stress) of example 06

Figure A.12: Deformed mesh of example 06

’ ’ ’ Example 06
S o l v e s a p l a n e s t r e s s 2D p r o b l e m u s i n g a s t r u c t u r e d mesh .
Shows how t o draw von M i s e s e f f e c t i v e s t r e s s a s an e l e m e n t v a l u e
with drawElementValues () .
Shows u s e o f GmshMesher a t t r i b u t e ’ nodesOnCurve ’ ( d i c t i o n a r y
t h a t s a y s w hi c h n o d e s a r e on a g i v e n g e o m e t r y c u r v e )
’’’

from p y c a l f e m import ∗
from p y c a l f e m u t i l s import ∗
from p y c a l f e m G e o D a t a import ∗

70
Examples A.6 Mesh Ex 06.py

from p y c a l f e m m e s h import ∗
import p y c a l f e m v i s a s pcv
import v i s v i s a s vv
from math import s q r t

# −−−− Problem c o n s t a n t s
t = 0.2
v = 0.35
E = 2 . 1 e9
ptype = 1
ep = [ pt y pe , t ]
D=hooke ( p t y p e , E , v )

p r i n t ”C r e a t i n g g e o m e t r y . . . ”
g = GeoData ( )

s 2 = 1/ s q r t ( 2 ) #J u s t a s h o r t h a n d . We u s e t h i s t o make t h e c i r c l e
arcs .

p o i n t s = [ [ 0 , 3 ] , [ 2 . 5 , 3 ] , [ 3 , 3 ] , [4− s2 , 3−s 2 ] , [ 4 , 2] , #
0−4
[4+ s2 , 3−s 2 ] , [ 5 , 3 ] , [ 5 . 5 , 3 ] , [ 8 , 3 ] , [ 0 , 1.5] , #
5−9
[2.5 , 1.5] , [4 , 1.5] , [5.5 , 1.5] , [8 , 1.5] , [0 , 0] , #
10−14
[ 2 . 5 , 0 ] , [ 3 , 0 ] , [4− s2 , s 2 ] , [ 4 , 1 ] , [4+ s2 , s2 ] , #
15−19
[5 , 0] , [5.5 , 0] , [8 ,0] , [4 ,3] , [4 ,0]] #
20−24
f o r xp , yp i n p o i n t s :
g . a d d P o i n t ( [ xp ∗ 0 . 1 , yp ∗ 0 . 1 ] )

splines = [[0 ,1] , [1 ,2] , [6 ,7] , [7 ,8] , [8 ,13] , #0−4


[ 1 3 , 2 2 ] , [ 2 2 , 2 1 ] , [ 2 1 , 2 0 ] , [ 1 6 , 1 5 ] , [ 1 5 , 1 4 ] , #5−9
[14 ,9] , [9 ,0] , [9 ,10] , [10 ,1] , [10 , 15] , #10−14
[10 ,11] , [11 ,4] , [11 ,18] , [11 ,12] , [12 ,7] , #15−19
[12 ,21] , [12 ,13] , [3 ,10] , [5 ,12] , [10 ,17] , #20−24
[12 ,19]] #25
for s in s p l i n e s :
g . a d d S p l i n e ( s , e l O n C u r v e =5)

g . s e t C u r v e M a r k e r ( ID =4, m a r k e r =7) #A s s i g n m a r k e r 7 t o t h e
s p l i n e s on t h e r i g h t .
g . s e t C u r v e M a r k e r ( ID =5, m a r k e r =7) # We w i l l a p p l y a f o r c e on
nodes with marker 7 .
g . s e t C u r v e M a r k e r ( ID =10 , m a r k e r =5) #A s s i g n m a r k e r 5 t o t h e
s p l i n e s on t h e l e f t .

71
A.6 Mesh Ex 06.py Examples

g . s e t C u r v e M a r k e r ( ID =11 , m a r k e r =5) # The n o d e s w i t h m a r k e r 5 w i l l


be l o c k e d i n p l a c e .

# P o i n t s i n c i r c l e a r c s a r e [ s t a r t , c e n t e r , end ]
c i r c l e a r c s = [ [ 2 , 23 , 3 ] , [ 3 , 23 , 4 ] , [ 4 , 23 , 5 ] , [ 5 , 23 , 6 ] ,
#26−29
[ 1 6 , 24 , 1 7 ] , [ 1 7 , 24 , 1 8 ] , [ 1 8 , 24 , 1 9 ] , [ 1 9 , 24 ,
20]] #30−33
for c in c i r c l e a r c s :
g . a d d C i r c l e ( c , e l O n C u r v e =5)

g. a d d S t r u c t u r e d S u r f a c e ( [ 1 1 , 1 2 , 1 3 , 0 ] ) #0
g. a d d S t r u c t u r e d S u r f a c e ( [ 1 4 , 12 , 10 , 9 ] )
g. a d d S t r u c t u r e d S u r f a c e ( [ 8 , 30 , 24 , 1 4 ] )
g. a d d S t r u c t u r e d S u r f a c e ( [ 2 4 , 31 , 17 , 1 5 ] )
g. a d d S t r u c t u r e d S u r f a c e ( [ 1 5 , 1 6 , 2 7 , 2 2 ] ) #4
g. a d d S t r u c t u r e d S u r f a c e ( [ 2 2 , 26 , 1 , 1 3 ] )
g. a d d S t r u c t u r e d S u r f a c e ( [ 1 6 , 18 , 23 , 2 8 ] )
g. a d d S t r u c t u r e d S u r f a c e ( [ 1 9 , 2 , 29 , 2 3 ] )
g. a d d S t r u c t u r e d S u r f a c e ( [ 1 9 , 2 1 , 4 , 3 ] ) #8
g. addStructuredSurface ([20 , 6 , 5 , 21])
g. a d d S t r u c t u r e d S u r f a c e ( [ 2 5 , 20 , 7 , 3 3 ] )
g. a d d S t r u c t u r e d S u r f a c e ( [ 3 2 , 1 7 , 1 8 , 2 5 ] ) #11

p r i n t ”Meshing g e o m e t r y . . . ”
e l T y p e = 3 #3 Quads
dofsPerNode = 2

mesher = GmshMesher ( geoData = g ,


elType = elType ,
d o f s P e r N o d e=d o f s Pe r N o de ,
gmshExecPath = None )
c o o r d s , e d o f , d o f s , b d o f s , e l e m e n t m a r k e r s = mesher . c r e a t e ( )

p r i n t ”A s s e m b l i n g s y s t e m m a t r i x . . . ”
nDofs = s i z e ( d o f s )
ex , ey = c o o r d x t r ( e d o f , c o o r d s , d o f s )
K = z e r o s ( [ nDofs , nDofs ] )

f o r e l t o p o , e l x , e l y i n z i p ( e d o f , ex , ey ) :
Ke = p l a n q e ( e l x , e l y , ep , D)
assem ( e l t o p o , K, Ke )

p r i n t ”S o l v i n g e q u a t i o n s y s t e m . . . ”
f = z e r o s ( [ nDofs , 1 ] )

bc = a r r a y ( [ ] , ’ i ’ )

72
Examples A.6 Mesh Ex 06.py

bcVal = a r r a y ( [ ] , ’ i ’ )

bc , b c V a l = a p p l y b c ( b d o f s , bc , bcVal , 5 , 0 . 0 , 0 )

a p p l y f o r c e ( b d o f s , f , 7 , 10 e5 , 1 )

a , r = s o l v e q (K, f , bc , b c V a l )

p r i n t ”Computing e l e m e n t f o r c e s . . . ”
ed = e x t r a c t E l d i s p ( e d o f , a )

vonMises = [ ]
f o r i i n r a n g e ( e d o f . s h a p e [ 0 ] ) : #For e a c h e l e m e n t :
es , e t = p l a n q s ( ex [ i , : ] , ey [ i , : ] , ep , D, ed [ i , : ] ) #D e t e r m i n e
e l e m e n t s t r e s s e s and s t r a i n s i n t h e e l e m e n t .
v o n M i s e s . append ( math . s q r t ( pow ( e s [ 0 ] , 2 ) − e s [ 0 ] ∗ e s [ 1 ] + pow
( e s [ 1 ] , 2 ) + 3∗ e s [ 2 ] ) ) #c a l c and append e f f e c t i v e s t r e s s
to l i s t .
## e s : [ s i g x s i g y t a u x y ]

print ”V i s u a l i s i n g . . . ”
pcv . drawGeometry ( g , d r a w P o i n t s=F a l s e , l a b e l C u r v e s=True )

vv . f i g u r e ( )
pcv . d r a w E l e m e n t V a l u e s ( v o n M is es , c o o r d s , e d o f , d o f s P e rN o de ,
e l T y p e , a , doDrawMesh=True , doDrawUndisplacedMesh=F a l s e ,
t i t l e =”Example 06 e f f e c t i v e s t r e s s ”)

vv . f i g u r e ( )
pcv . d r a w D i s p l a c e m e n t s ( a , c o o r d s , e d o f , do fs Pe r N o d e , e l T y p e ,
doDrawUndisplacedMesh=True , t i t l e =”Example 06 ”)

# Make u s e o f a t t r i b u t e ’ nodesOnCurve ’ i n GmshMesher t o draw


some a r r o w s on t h e r i g h t hand s i d e o f t h e mesh :
rightSideNodes = set ()
f o r c u r v e I D i n [ 4 , 5 ] : #4 and 5 a r e t h e I D s o f t h e c u r v e s where
we a p p l i e d t h e f o r c e s .
r i g h t S i d e N o d e s = r i g h t S i d e N o d e s . u n i o n ( s e t ( mesher .
nodesOnCurve [ c u r v e I D ] ) ) #Get t h e nodes , w i t h o u t
duplicates .
for i in rightSideNodes :
x = coords [ i , 0 ] + a [ i ∗2 , 0 ] #P o s i t i o n o f t h e node w i t h
displacements .
y = c o o r d s [ i , 1 ] + a [ i ∗2+1 , 0 ]
pcv . addText ( ”\ r i g h t a r r o w ” , ( x , y ) , f o n t S i z e =20 , c o l o r= ’ g ’ ) #
A p o o r man ’ s f o r c e i n d i c a t o r . Could a l s o u s e vv . p l o t ( )

73
A.7 Mesh Ex 07.py Examples

# E n t e r main l o o p :
app = vv . u s e ( )
app . C r e a t e ( )
app . Run ( )

p r i n t ”Done . ”

A.7 Mesh Ex 07.py

Figure A.13: Geometry of example 07

Figure A.14: Mesh of example 07

74
Examples A.7 Mesh Ex 07.py

Figure A.15: Node values (temperature) of example 07

’ ’ ’ Example 07
Meshing 8−node−i s o p a r a m e t r i c e l e m e n t s ( s e c o n d o r d e r i n c o m p l e t e
quads ) .
Shows u s e o f s u r f a c e m a r k e r s / e l e m e n t m a r k e r s t o a p p l y d i f f e r e n t
p r o p e r t i e s to elements i n d i f f e r e n t r e g i o n s .
’’’
from p y c a l f e m G e o D a t a import ∗
from p y c a l f e m m e s h import ∗
from p y c a l f e m v i s import ∗
import v i s v i s a s vv
from p y c a l f e m import ∗
from p y c a l f e m u t i l s import ∗

# −−−− Problem c o n s t a n t s
kx1 = 100
ky1 = 100
kx2 = 10
ky2 = 10
t = 1.0
n = 2 #Gauss p o i n t s o r i n t e g r a t i o n p o i n t s
ep = [ t , n ]

D1 = m a t r i x ( [
[ kx1 , 0 . ] ,
[ 0 . , ky1 ] ] )
D2 = m a t r i x ( [
[ kx2 , 0 . ] ,
[ 0 . , ky2 ] ] )

75
A.7 Mesh Ex 07.py Examples

D d i c t = {10 : D1 , 11 : D2} #m a r k e r s 10 & 11 w i l l be u s e d t o


s p e c i f y d i f f e r e n t r e g i o n s with d i f f e r e n t c o n d u c t i v i t y .

# −−−− C r e a t e Geometry
g = GeoData ( )

#Add P o i n t s :
p o i n t s = [ [ 0 , 0 ] , [ 0 , 1 0 0 ] , [ 0 , 1 5 0 ] , [ 1 0 0 , 0 ] , [ 1 5 0 , 0 ] , [100 , −100] ,
[150 , −100]]
for p in points :
g . addPoint (p)

#Add S p l i n e s :
g . addSpline ([1 , 2 ] , m a r k e r =2, e l O n C u r v e =4)
g . addSpline ([3 , 4 ] , e l O n C u r v e =4)
g . addCircle ([1 , 0 , 3 ] , elOnCurve = 10)
g . addCircle ([2 , 0 , 4 ] , elOnCurve = 10)
g . addSpline ([3 , 5 ] , elOnCurve = 6)
g . addSpline ([5 , 6 ] , m a r k e r =3, e l O n C u r v e = 4 )
g . addSpline ([6 , 4 ] , elOnCurve = 6)

#Add S u r f a c e s :
# When we s e t m a r k e r s f o r s u r f a c e s , and ha ve 2D e l e m e n t s , we can
f i n d w h ic h r e g i o n
# an e l e m e n t i s i n v i a t h e l i s t ’ e l e m e n t m a r k e r s ’ , w h ic h i s
r e t u r n e d by GmshMesher . c r e a t e ( )
g . a d d S t r u c t u r e d S u r f a c e ( [ 0 , 2 , 1 , 3 ] , marker = 10)
g . a d d S t r u c t u r e d S u r f a c e ( [ 1 , 4 , 5 , 6 ] , marker = 11)

e l T y p e = 16 #E l e m e n t t y p e 16 i s 8−node−quad . ( See gmsh manual


f o r more e l e m e n t t y p e s )
d o f s P e r N o d e= 1 #D e g r e e s o f f r e e d o m p e r node .

mesher = GmshMesher ( geoData = g ,


gmshExecPath = None , #Path t o gmsh . e x e . I f
None t h e n t h e s y s t e m PATH v a r i a b l e i s
q u e r i e d . R e l a t i v e and a b s o l u t e p a t h s work
.
elType = elType ,
d o f s P e r N o d e= d o f s P e r N o d e )
c o o r d s , e d o f , d o f s , b d o f s , e l e m e n t m a r k e r s = mesher . c r e a t e ( )

p r i n t ”A s s e m b l i n g s y s t e m m a t r i x . . . ”
nDofs = s i z e ( d o f s )
ex , ey = c o o r d x t r ( e d o f , c o o r d s , d o f s )

K = z e r o s ( [ nDofs , nDofs ] )

76
Examples A.7 Mesh Ex 07.py

f o r e l t o p o , e l x , e l y , e l M a r k e r i n z i p ( e d o f , ex , ey ,
elementmarkers ) :
#C a l c e l e m e n t s t i f f n e s s m a t r i x : C o n d u c t i v i t y m a t r i x D i s
taken
# from D d i c t and d e p e n d s on w h i c h r e g i o n ( w h ic h m a r k e r ) t h e
element i s in .
Ke = f l w 2 i 8 e ( e l x , e l y , ep , D d i c t [ e l M a r k e r ] )
assem ( e l t o p o , K, Ke )

p r i n t ”S o l v i n g e q u a t i o n s y s t e m . . . ”
f = z e r o s ( [ nDofs , 1 ] )

bc = a r r a y ( [ ] , ’ i ’ )
bcVal = a r r a y ( [ ] , ’ i ’ )

bc , b c V a l = a p p l y b c ( b d o f s , bc , bcVal , 2 , 3 0 . 0 )
bc , b c V a l = a p p l y b c ( b d o f s , bc , bcVal , 3 , 0 . 0 )

a , r = s o l v e q (K, f , bc , b c V a l )

p r i n t ”Computing e l e m e n t f o r c e s . . . ”
ed = e x t r a c t E l d i s p ( e d o f , a )

f o r i i n r a n g e ( s h a p e ( ex ) [ 0 ] ) :
es , et , e c i = f l w 2 i 8 s ( ex [ i , : ] , ey [ i , : ] , ep , D d i c t [
e l e m e n t m a r k e r s [ i ] ] , ed [ i , : ] )
#Do s o m e t h i n g w i t h es , et , e c i h e r e .

print ”V i s u a l i s i n g . . . ”
drawGeometry ( g , t i t l e =”Geometry ”)

vv . f i g u r e ( )
drawMesh ( c o o r d s , e d o f , d o f s Pe r N o de , e l T y p e , f i l l e d =F a l s e )
#8−node quads a r e drawn a s s i m p l e quads .

vv . f i g u r e ( )
d r a w N o d a l V a l u e s ( a , c o o r d s , e d o f , d o f s P e rN o d e , e l T y p e , t i t l e =”
Example 7 ”)
g e t C o l o r b a r ( ) . S e t L a b e l ( ”T e m p e r a t u r e ”)
addText ( ”The bend h a s h i g h c o n d u c t i v i t y ” , ( 1 2 5 , 1 2 5 ) )
addText ( ”T h i s p a r t h a s low c o n d u c t i v i t y ” , (160 , −50) )

# E n t e r main l o o p :
app = vv . u s e ( )
app . C r e a t e ( )
app . Run ( )

77
A.8 Mesh Ex 08.py Examples

p r i n t ”Done . ”

A.8 Mesh Ex 08.py

Figure A.16: Deformed mesh of example 08

’ ’ ’ Example 08
Shows how t o l o a d g e o m e t r y from a gmsh geo f i l e .
The g e o m e t r y i s t h e same a s i n e x a m p l e 0 6 .
’’’

from p y c a l f e m import ∗
from p y c a l f e m u t i l s import ∗
from p y c a l f e m m e s h import ∗
import p y c a l f e m v i s a s pcv
import v i s v i s a s vv

# −−−− C r e a t e Geometry
g = ”e x a m p l e g e o \ ex8 . geo ” #R e l a t i v e p a t h t o t h e geo f i l e t h a t
c o n t a i n s the geometry .

e l T y p e = 3 #3 Quads
dofsPerNode = 2

mesher = GmshMesher ( geoData = g ,


gmshExecPath = None ,
elType = elType ,
d o f s P e r N o d e= d o f s P e r N o d e )

78
Examples A.8 Mesh Ex 08.py

c o o r d s , e d o f , d o f s , b d o f s , e l e m e n t m a r k e r s = mesher . c r e a t e ( )

#The r e s t o f t h e e x a m p l e i s t h e same a s e x a m p l e 0 6 .
t = 0.2
v = 0.35
E = 2 . 1 e9
ptype = 1
ep = [ pt y pe , t ]
D=hooke ( p t y p e , E , v )

p r i n t ”A s s e m b l i n g s y s t e m m a t r i x . . . ”
nDofs = s i z e ( d o f s )
ex , ey = c o o r d x t r ( e d o f , c o o r d s , d o f s )
K = z e r o s ( [ nDofs , nDofs ] )

f o r e l t o p o , e l x , e l y i n z i p ( e d o f , ex , ey ) :
Ke = p l a n q e ( e l x , e l y , ep , D)
assem ( e l t o p o , K, Ke )

p r i n t ”S o l v i n g e q u a t i o n s y s t e m . . . ”
f = z e r o s ( [ nDofs , 1 ] )
bc = a r r a y ( [ ] , ’ i ’ )
bcVal = a r r a y ( [ ] , ’ i ’ )
bc , b c V a l = a p p l y b c ( b d o f s , bc , bcVal , 5 , 0 . 0 , 0 )
a p p l y f o r c e ( b d o f s , f , 7 , 10 e5 , 1 )
a , r = s o l v e q (K, f , bc , b c V a l )

print ”V i s u a l i s i n g . . . ”
pcv . d r a w D i s p l a c e m e n t s ( a , c o o r d s , e d o f , do fs Pe r N o d e , e l T y p e ,
doDrawUndisplacedMesh=True , t i t l e =”Example 08 − Geometry from
06 ”)

# E n t e r main l o o p :
app = vv . u s e ( )
app . C r e a t e ( )
app . Run ( )

p r i n t ”Done . ”

79
A.9 Mesh Ex 09.py Examples

A.9 Mesh Ex 09.py

Figure A.17: Deformed mesh of example 09

’ ’ ’ Example 09
Shows how t o embed v i s v i s f i g u r e s i n a wxPython GUI .
V i s v i s can a l s o be embedded i n Qt4 ( PyQt ) , GTK, and FLTK .
Based on h t t p : / / code . g o o g l e . com/p/ v i s v i s / w i k i /
example embeddingInWx
’’’

import wx
from p y c a l f e m import ∗
from p y c a l f e m u t i l s import ∗
from p y c a l f e m m e s h import ∗
import p y c a l f e m v i s a s pcv
import v i s v i s a s vv

# C r e a t e a v i s v i s app i n s t a n c e , w h ic h wraps a wx a p p l i c a t i o n
object .
# T h i s n e e d s t o be done ∗ b e f o r e ∗ i n s t a n t i a t i n g t h e main window .
app = vv . u s e ( ’ wx ’ )

c l a s s MainWindow ( wx . Frame ) :
def init ( self ) :
wx . Frame . init ( s e l f , None , −1, ”Embedding i n WX” ,
s i z e =(560 , 4 2 0 ) )

# Make a p a n e l w i t h b u t t o n s
s e l f . p a n e l = wx . P a n e l ( s e l f )

80
Examples A.9 Mesh Ex 09.py

b u t 1 = wx . Button ( s e l f . p a n e l , −1, ’ C a l c ’ )
b u t 2 = wx . Button ( s e l f . p a n e l , −1, ’ P l o t ’ )
b u t 3 = wx . Button ( s e l f . p a n e l , −1, ’ C l e a r ’ )

#Make p a n e l s i z e r and embed s t u f f


s e l f . p a n e l s i z e r = wx . B o x S i z e r ( wx . VERTICAL )
s e l f . p a n e l s i z e r . Add ( b u t 1 )
s e l f . p a n e l s i z e r . Add ( b u t 2 )
s e l f . p a n e l s i z e r . Add ( b u t 3 )
s e l f . panel . SetSizer ( s e l f . p a n e l s i z e r )

# Make f i g u r e u s i n g ” s e l f ” a s a p a r e n t
F i g u r e = app . G e t F i g u r e C l a s s ( )
s e l f . f i g = Figure ( s e l f )

# Make window s i z e r and embed s t u f f


s e l f . s i z e r = wx . B o x S i z e r ( wx . HORIZONTAL)
s e l f . s i z e r . Add ( s e l f . p a n e l , 1 , wx . EXPAND)
s e l f . s i z e r . Add ( s e l f . f i g . w i d g e t , 2 , wx . EXPAND)

# Make c a l l b a c k
b u t 1 . Bind ( wx . EVT BUTTON, s e l f . C a l c )
b u t 2 . Bind ( wx . EVT BUTTON, s e l f . P l o t )
b u t 3 . Bind ( wx . EVT BUTTON, s e l f . C l e a r )

# Ap p l y window s i z e r s
s e l f . SetSizer ( s e l f . sizer )
s e l f . S e t A u t o L a y o u t ( True )
s e l f . Layout ( )

# Finish
s e l f . Show ( )

def Calc ( s e l f , event ) :


#C a l c u l a t i o n s a r e t a k e n from e x a m p l e 0 8 .
# Constants :
t = 0.2
v = 0.35
E = 2 . 1 e9
ptype = 1
ep = [ pt y pe , t ]
D=hooke ( p t y p e , E , v )

# C r e a t e Geometry :
g = ”e x a m p l e g e o \ ex8 . geo ”
s e l f . e l T y p e = 3 #3 Quads
s e l f . dofsPerNode = 2

81
A.9 Mesh Ex 09.py Examples

mesher = GmshMesher ( geoData = g ,


gmshExecPath = None , #”gmsh\gmsh . e x e

elType = s e l f . elType ,
d o f s P e r N o d e= s e l f . d o f s P e r N o d e )
s e l f . coords , s e l f . edof , s e l f . dofs , s e l f . bdofs , =
mesher . c r e a t e ( )

# Assem s y s t e m s m a t r i x :
nDofs = s i z e ( s e l f . d o f s )
ex , ey = c o o r d x t r ( s e l f . e d o f , s e l f . c o o r d s , s e l f . d o f s )
K = z e r o s ( [ nDofs , nDofs ] )
f o r e l t o p o , e l x , e l y i n z i p ( s e l f . e d o f , ex , ey ) :
Ke = p l a n q e ( e l x , e l y , ep , D)
assem ( e l t o p o , K, Ke )

# Solve :
f = z e r o s ( [ nDofs , 1 ] )
bc = a r r a y ( [ ] , ’ i ’ )
bcVal = a r r a y ( [ ] , ’ i ’ )
bc , b c V a l = a p p l y b c ( s e l f . b d o f s , bc , bcVal , 5 , 0 . 0 , 0 )
a p p l y f o r c e ( s e l f . b d o f s , f , 7 , 10 e5 , 1 )
self .a, = s o l v e q (K, f , bc , b c V a l )

def Plot ( s e l f , event ) :


# Make s u r e o u r f i g u r e i s t h e a c t i v e one
# I f o n l y one f i g u r e , t h i s i s n o t n e c e s s a r y .
#vv . f i g u r e ( s e l f . f i g . n r )

# Clear i t :
vv . c l f ( )

# Plot :
pcv . d r a w D i s p l a c e m e n t s ( s e l f . a , s e l f . c o o r d s , s e l f . e d o f ,
s e l f . d o fs P e r N o d e , s e l f . e l T y p e , doDrawUndisplacedMesh=
True , t i t l e =”Example 09 ”)

def Clear ( s e l f , event ) :


vv . c l f ( ) #C l e a r c u r r e n t f i g u r e

# Two ways t o c r e a t e t h e a p p l i c a t i o n and s t a r t t h e main l o o p


i f True :
# The v i s v i s way . W i l l r u n i n i n t e r a c t i v e mode when u s e d i n
IEP o r I P y t h o n .
app . C r e a t e ( )
m = MainWindow ( )
app . Run ( )

82
Examples A.10 Mesh Ex 10.py

else :
# The n a t i v e way .
wxApp = wx . App ( )
m = MainWindow ( )
wxApp . MainLoop ( )

A.10 Mesh Ex 10.py

Figure A.18: Geometry of example 10. Same as the use case

Figure A.19: Mesh of example 10. Same as the use case

83
A.10 Mesh Ex 10.py Examples

Figure A.20: Deformed mesh of example 10. Same as the use case

Figure A.21: Element values (effective stress) of example 10. Same as the use case

’ ’ ’ Example 10
The u s e c a s e from t h e u s e r manual .
The e x a m p l e d o e s n o t c o n t a i n a n y t h i n g t h a t i s n o t c o v e r e d i n t h e
p r e v i o u s examples .
’’’

import p y c a l f e m G e o D a t a
import p y c a l f e m m e s h
import p y c a l f e m v i s a s pcv
import v i s v i s a s vv
from p y c a l f e m import ∗

84
Examples A.10 Mesh Ex 10.py

from p y c a l f e m u t i l s import ∗

#DEFINE GEOMETRY:
g = p y c a l f e m G e o D a t a . GeoData ( ) #C r e a t e a GeoData o b j e c t t h a t
h o l d s the geometry .

#Add p o i n t s :
g . addPoint ( [ 0 , 0]) #0
g . addPoint ( [ 1 , 0]) #1
g . addPoint ( [ 1 , 1]) #2
g . addPoint ( [ 0 , 1]) #3
g . addPoint ( [ 0 . 2 , 0.2]) #4
g . addPoint ( [ 0 . 8 , 0.2]) #5
g . addPoint ( [ 0 . 8 , 0.8]) #6
g . addPoint ( [ 0 . 2 , 0.8]) #7

#Add c u r v e s :
g . addSpline ([0 , 1 ] , m a r k e r =70) #0
g . addSpline ([2 , 1]) #1
g . addSpline ([3 , 2 ] , m a r k e r =90) #2
g . addSpline ([0 , 3]) #3
g . addSpline ([4 , 5]) #4
g . addSpline ([5 , 6]) #5
g . addSpline ([6 , 7]) #6
g . addSpline ([7 , 4]) #7

#Add s u r f a c e s :
g . addSurface ( [ 0 , 1 , 2 , 3 ] , h o l e s = [ [ 4 , 5 , 6 , 7 ] ] , marker = 55)
g . addSurface ( [ 4 , 5 , 6 , 7 ] , marker = 66)

#MESHING :
e l T y p e = 3 #E le m e n t t y p e 3 i s quad .
d o f s P e r N o d e = 2 #D e g r e e s o f f r e e d o m p e r node .

mesher = p y c a l f e m m e s h . GmshMesher ( geoData = g ,


gmshExecPath = None , #Path t o gmsh .
e x e . I f None t h e n t h e s y s t e m PATH
variable i s queried . Relative
and a b s o l u t e p a t h s work .
e l S i z e F a c t o r = 0 . 0 4 , #F a c t o r t h a t
changes element s i z e s .
elType = elType ,
d o f s P e r N o d e= d o f s P e r N o d e )

#Mesh t h e g e o m e t r y :
# The f i r s t f o u r r e t u r n v a l u e s a r e t h e same a s t h o s e t h a t
trimesh2d () returns .

85
A.10 Mesh Ex 10.py Examples

# v a l u e e l e m e n t m a r k e r s i s a l i s t o f m a r k e r s , and i s u s e d f o r
f i n d i n g the marker o f a g i v e n element ( i n d e x ) .
c o o r d s , e d o f , d o f s , b d o f s , e l e m e n t m a r k e r s = mesher . c r e a t e ( )

#SOLVE :
t = 0.2
v = 0.35
E1 = 2 e9
E2 = 0 . 2 e9
ptype = 1
ep = [ pt y pe , t ]
D1 = hooke ( pt y pe , E1 , v )
D2 = hooke ( pt y pe , E2 , v )
D d i c t = {55 : D1 , 66 : D2}

nDofs = s i z e ( d o f s )
K = z e r o s ( [ nDofs , nDofs ] )
ex , ey = c o o r d x t r ( e d o f , c o o r d s , d o f s )

f o r e l t o p o , e l x , e l y , e l M a r k e r i n z i p ( e d o f , ex , ey ,
elementmarkers ) :
#C a l c e l e m e n t s t i f f n e s s m a t r i x : C o n d u c t i v i t y m a t r i x D i s
taken
# from D d i c t and d e p e n d s on w h i c h r e g i o n ( w h ic h m a r k e r ) t h e
element i s in .
Ke = p l a n q e ( e l x , e l y , ep , D d i c t [ e l M a r k e r ] )
assem ( e l t o p o , K, Ke )

bc = a r r a y ( [ ] , ’ i ’ )
bcVal = a r r a y ( [ ] , ’ i ’ )
bc , b c V a l = a p p l y b c ( b d o f s , bc , bcVal , 7 0 , 0 . 0 )

f = z e r o s ( [ nDofs , 1 ] )
a p p l y f o r c e ( b d o f s , f , 9 0 , v a l u e = −10e5 , d i m e n s i o n =2)
a , r = s o l v e q (K, f , bc , b c V a l )

ed = e x t r a c t E l d i s p ( e d o f , a )
vonMises = [ ]
f o r i i n r a n g e ( e d o f . s h a p e [ 0 ] ) : #For e a c h e l e m e n t :
es , e t = p l a n q s ( ex [ i , : ] , ey [ i , : ] , ep , D d i c t [ e l e m e n t m a r k e r s [ i
] ] , ed [ i , : ] ) #D e t e r m i n e e l e m e n t s t r e s s e s and s t r a i n s i n
the element .
v o n M i s e s . append ( math . s q r t ( pow ( e s [ 0 ] , 2 ) − e s [ 0 ] ∗ e s [ 1 ] + pow
( e s [ 1 ] , 2 ) + 3∗pow ( e s [ 2 ] , 2 ) ) )

#VISUALISATION :

86
Examples A.10 Mesh Ex 10.py

pcv . drawGeometry ( g , t i t l e =”Geometry ”)


vv . f i g u r e ( ) #New f i g u r e window
pcv . drawMesh ( c o o r d s=c o o r d s , e d o f=e d o f , d o f s P e r N o d e=do f s Pe r N o d e ,
e l T y p e=e l T y p e , f i l l e d =True , t i t l e =”Mesh ”) #Draws t h e mesh .
vv . f i g u r e ( )
pcv . d r a w D i s p l a c e m e n t s ( a , c o o r d s , e d o f , do fs Pe r N o d e , e l T y p e ,
doDrawUndisplacedMesh=F a l s e , t i t l e =”D i s p l a c e m e n t s ”)
vv . f i g u r e ( )
pcv . d r a w E l e m e n t V a l u e s ( v o n M is es , c o o r d s , e d o f , d o f s P e rN o de ,
e l T y p e , a , doDrawMesh=True , doDrawUndisplacedMesh=F a l s e ,
t i t l e =” E f f e c t i v e S t r e s s ”)
pcv . g e t C o l o r b a r ( ) . S e t L a b e l ( ” E f f e c t i v e s t r e s s ”)

# E n t e r main l o o p :
app = vv . u s e ( )
#app . C r e a t e ( )
app . Run ( )

87
Appendix B

Status of existing CALFEM functions

Summary status of existing element functions. Functions replaced by “-” are not yet imple-
mented. Functions with an “*” will most likely be removed from the next release of CALFEM.
An implementation has been started for functions with a “†” but they are not completed yet.

Python MATLAB
spring1e(ep) spring1e(ep)
spring1s(ep, ed) spring1s(ep, ed)
bar1e(ep) bar1e(ep)
bar1s(ep, ed) bar1s(ep, ed)
bar2e(ex, ey, ep) bar2e(ex, ey, ep)
bar2g(ex, ey, ep, N) bar2g(ex, ey, ep, N)
bar2s(ex, ey, ep, ed) bar2s(ex, ey, ep, ed)
bar3e(ex, ey, ez, ep) bar3e(ex, ey, ez, ep)
bar3s(ex, ey, ez, ep, ed) bar3s(ex, ey, ez, ep, ed)
flw2te(ex, ey, ep, D, eq) flw2te(ex, ey, ep, D, eq)
flw2ts(ex, ey, D, ed) flw2ts(ex, ey, D, ed)
flw2qe(ex, ey, ep, D, eq) flw2qe(ex, ey, ep, D, eq)
flw2qs(ex, ey, ep, D, ed, eq) flw2qs(ex, ey, ep, D, ed, eq)
flw2i4e(ex, ey, ep, D, eq) flw2i4e(ex, ey, ep, D, eq)
flw2i4s(ex, ey, ep, D, ed) flw2i4s(ex, ey, ep, D, ed)
flw2i8e(ex, ey, ep, D, eq) flw2i8(ex, ey, ep, D, eq)
flw2i8s(ex, ey, ep, D, ed) flw2i8s(ex, ey, ep, D, ed)
flw3i8e(ex, ey, ez, ep, D, eq) flw3i8e(ex, ey, ez, ep, D, eq)
flw3i8s(ex, ey, ez, ep, D, ed) flw3i8s(ex, ey, ez, ep, D, ed)
plante(ex, ey, ep, D, eq) plante(ex, ey, ep, D, eq)
plants(ex, ey, ep, D, ed) plants(ex, ey, ep, D, ed)
plantf(ex, ey, ep, es) plantf(ex, ey, ep, es)
planqe(ex, ey, ep, D, eq) planqe(ex, ey, ep, D, eq)*
planqs(ex, ey, ep, D, ed, eq) planqs(ex, ey, ep, D, ed, eq) *
- planre(ex, ey, ep, D, eq)
- planrs(ex, ey, ep, D, ed)

89
Status of existing CALFEM functions

- plantce(ex, ey, ep, eq) *


- plantcs(ex, ey, ep, ed) *
plani4e(ex, ey, ep, D, eq) plani4e(ex, ey, ep, D, eq)
- plani4s(ex, ey, ep, D, ed)
- plani4f(ex, ey, ep, es)
- plani8e(ex, ey, ep, D, eq) *
- plani8s(ex, ey, ep, D, ed) *
- plani8f(ex, ey, ep, es) *
- soli8e(ex, ey, ez, ep, D, eq) *
- soli8s(ex, ey, ez, ep, D, ed) *
- soli8f(ex, ey, ez, ep, es) *
beam2e(ex, ey, ep, eq) beam2e(ex, ey, ep, eq)
beam2s(ex, ey, ep ,ed, eq, np) beam2s(ex, ey, ep, ed, eq, n)
beam2t(ex, ey, ep, eq) beam2t(ex, ey, ep, eq)
beam2ts(ex, ey, ep, ed, eq, np) beam2ts(ex, ey, ep, ed, eq, n)
beam2w(ex, ey, ep, eq) beam2w(ex, ey, ep, eq)
beam2ws(ex, ey, ep, ed, eq) beam2ws(ex, ey, ep, ed, eq)
beam2g(ex, ey, ep, N, eq) beam2g(ex, ey, ep, N, eq)
beam2gs(ex, ey, ep, ed, N, eq) beam2gs(ex, ey, ep, ed, N, eq)
beam2d(ex, ey, ep) beam2d(ex, ey, ep)
- beam2ds(ex, ey, ep, ed, ev, ea)
beam3e(ex, ey, ez, eo, ep, eq) beam3e(ex, ey, ez, eo, ep, eq)
beam3s(ex, ey, ez, eo, ep, ed, eq, n) beam3s(ex, ey, ez, eo, ep, ed, eq, n)
platre(ex, ey, ep, D, eq) platre(ex, ey, ep, D, eq)
- platrs(ex, ey, ep, D, ed)
- red(A, b)
hooke(ptype, E, v) hooke(ptype, E, v)
- mises(ptype, mp, est, st)
- dmises(ptype, mp, es, st)
assem(edof, K, Ke, f, fe) assem(edof, K, Ke, f, fe)
coordxtr(edof, coords, dofs) cordxtr(Edof, Coord, Dof, nen)
- eigen(K, M, b)
extract(edof, a) extract(edof, a)
- insert(edof, f, ef)
solveq(K, f, bcPresc, bcVal) solveq(K, f, bc)
statcon(K, f, cd) statcon(K, f, b)
- dyna2(w2, xi, f, g, dt)
- dyna2f(w2, xi, f, p, dt)
- freqresp(D, dt)
- gfunc(G, dt)
- ritz(K, M, f, m, b)
- spectra(a, xi, dt, f)
- step1(K, C, d0, ip, f, pbound)
- step2(K, C, d0, v0, ip, f, pdisp)
- sweep(K, C, M, p, w)

90
Status of existing CALFEM functions

- eldia2(ex, ey, es, plotpar, sfac, eci)


eldisp2(ex, ey, ed, magnfac, showmesh) † eldisp2(Ex, Ey, Ed, plotpar, sfac)
eldraw2(ex, ey) † eldraw2(Ex, Ey, plotpar, elnum)
- elflux2(Ex, Ey, Es, plotpar, sfac)
eliso2(ex, ey, ed, showmesh) † eliso2(Ex, Ey, Ed, isov, plotpar)
- elprinc2(Ex, Ey, Es, plotpar, sfac)
- pltscalb2(sfac, magnitude, plotpar)
scalfact2(ex, ey, ed, rat) † scalfact2(ex, ey, ed, rat)

91

You might also like