Following my earlier book “An Introduction to Mathematica for Civil Engineers” I have compiled another, “Using Finite Elements to Analyse Structures in Mathematica.” Both books are available for free, on the Notebook Archive. This second book is not a treatise on finite element theory but rather, a practical manual on how to use Wolfram’s excellent finite element solver, which is a standard part of Mathematica, on typical engineering problems.
The book commences by solving simple problems such as slabs or walls. This introduces the process and shows how to go from the solution for displacement to bending moments. The models become more complex as the book progresses. Various boundary conditions are discussed, and ways of applying loads are shown. Different methods of constructing the model, either from within Mathematica or by importing models constructed in a CAD program, are demonstrated.
Several cases of structure/soil interaction are shown with the soil modelled in various ways and particular attention is applied to getting the output in a suitable form eg. by applying Wood Armer corrections to stress for reinforced slabs or walls, or getting polar and tangential moments for circular structures.
Structures tackled include circular and rectangular tanks or basements, on rigid foundations, elastic springs or emebedded in soil, rafts and piled rafts, and structures such as sea walls or soil nail anchor blocks. Finishing with thick shell structures.
The book is free, as is the previous introductory book. It is aimed at students and practising engineers to give them the confidence to use finite elements in their day to day work, without the cost of investing in a specialist program. I hope you find it useful.
​
The book is available on the Notebook archive at https://www.notebookarchive.org/2026-01-dtiqavj. It’s free and there are no restrictions on its use. I hope engineers, professors, and students find it helpful. CITATION (original book): Malcolm Woodruff, “Using Finite Elements to Analyse Structures” from the Notebook Archive (2026), https://notebookarchive.org/2026-01-dtiqavj

Sample chapter 8: Circular tank on elastic ground

This chapter shows the same tank but, instead of sitting on springs, it is sitting on the ground, which is represented by an elastic medium with appropriate parameters.
Using CSGRegion[“Union”,{tank,ground}] merges the tank and the ground without any boundary between them so CSGRegion should only be used for a single solid, all of one material. To model the tank and ground properly, OpenCascadeLink is used here.
​
​OpenCascadeLink is Wolfram’s interface with the Open Cascade Technology’s robust set of Open Source tools for 3D surface and solid modelling and geometry processing. To use you only need to load the Module. So we will add that to the initialisation routine

Initialisation

In[]:=
Needs["NDSolve`FEM`"]​​fullPath=FileNameJoin[{NotebookDirectory[],"Appendix_A_Useful_functions.nb"}];​​NotebookEvaluate[fullPath];​​Needs["OpenCascadeLink`"]

Geometry

Define the geometry of the tank as before. Also define the extents of the ground.
In[]:=
r=10;(*radiusofthecylinder*)​​tw=0.25;(*Thicknessofthecylinderwalls*)​​tf=0.25;(*Thicknessofthecylinderbase*)​​h=4;(*Heightoftank*)​​groundX=15;(*groundwidthinthexdirection*)​​groundY=15;(*groundwidthintheYdirection*)​​groundZ=15;(*grounddepthintheZdirection*)
The inner and outer cylinders are then formed and the tank constructed in a similar manner as before, but using Open Cascade’s versions of the appropriate functions.
In[]:=
outerCylinder=OpenCascadeShape[Cylinder[{{0,0,0},{0,0,h}},r]];
In[]:=
innerCylinder=OpenCascadeShape[Cylinder[{{0,0,tf},{0,0,h}},r-tw]];
In[]:=
(*Createthetankasadifference*)​​tank=OpenCascadeShapeDifference[outerCylinder,innerCylinder]
Out[]=
OpenCascadeShapeExpression[19]
Any of these functions result in an OpenCascadeShapeExpression. To view then you need to convert to a Boundary Mesh as follows.
In[]:=
Show[OpenCascadeShapeSurfaceMeshToBoundaryMesh[tank]["Wireframe"["MeshElementStyle"{FaceForm[Red]}]]]
Out[]=
A function can be used, more conveniently, to do this with much less typing i.e.
In[]:=
visualizeOC[oc_(*OpenCascadeShapeExpression*),edgeColour_,faceColour_]:=OpenCascadeShapeSurfaceMeshToBoundaryMesh[oc]["Wireframe"["MeshElementStyle"->Directive[EdgeForm[edgeColour],FaceForm[faceColour]]]]
In[]:=
visualizeOC[tank,Blue,LightGray]
Out[]=
The ground can be constructed.
In[]:=
ground=OpenCascadeShape[Cuboid[{-groundX,-groundY,-groundZ},{groundX,groundY,0}]]
Out[]=
OpenCascadeShapeExpression[20]
and then visualised
In[]:=
visualizeOC[ground,White,Brown]
Out[]=
These shapes could be put together using OpenCascadeShapeUnion[{tank,ground}] but this would merge the regions, similarly to using CSG Region[“Union”,{tank,ground}]. Instead, the model can be created with a common interface where they join, by flattening the faces of each shape before joining them together.
In[]:=
ocModel=OpenCascadeShapeUnion[Flatten[OpenCascadeShapeFaces/@{tank,ground}]]
Out[]=
OpenCascadeShapeExpression[41]
In[]:=
visualizeOC[ocModel,Black,LightBlue]
Out[]=

Boundary mesh

Once you have the ocModel you can get the boundary mesh and then mesh that.
Get the boundary mesh of the ocModel
In[]:=
bmesh=OpenCascadeShapeSurfaceMeshToBoundaryMesh[ocModel]
Out[]=
ElementMesh[{{-15.,15.},{-15.,15.},{-15.,4.}},Automatic]
Visualise it if required.
In[]:=
bmesh["Wireframe"]
Out[]=

Separation into groups

To aid examination of the model, each part of the model can be separated into a group and given a colour.
The expressions to do this are as follows.
and this can be visualised.
To check that we have an interface between the tank and the ground we can just plot part of the model

Meshing and mesh element markers

Now we have a model made up of two parts with a common boundary. To work on each element i.e. to mesh separately, or to give different parameters we need to be able to define each part. This is done by using a point within each part of the model. This can be any point, but must lie within the solid of each part. Here we use the centroid of the tank floor and the centroid of the ground.
The meshing can then be undertaken. The format is
​{“point in part”, “RegionMarker”, maxCellMeasure}​
The meshElementMarker should be an integer. Any number can be used. Here we will increment by one for each part. The maxCellMeasure is optional. Here we have increased the cell measure considerably in the ground.
The following expression should result in a list of mesh element markers. If it includes a zero then there is a mistake somewhere. Possibly a part of the model has been missed or a point has been defined outside the model.
The mesh can now be visualised.
Each part of the model can be examined separately, if required.
Part of the model can be shown, if desired.
Element markers can be found, as before.

Output variables

Parameters

Note that the ground has already settled under its own weight and here we are interested in the settlement caused by the construction of the tank. So the ground is given a zero density. Hence the stresses calculated in the ground are the additional stresses caused by the tank. If we want the actual stresses in the ground we should run the computation without the tank and then take the stresses calculated from that, and enter them as initial stresses.

Operators

Boundary Conditions

Loads
Displacement Conditions

Solution

The calculation takes about 81 seconds.

Post processing

The displacement in the centre of the floor is
and at the top of the wall

Deformation

The contours of displacement in the ground can be plotted.

Note:

Whilst the above may seem long winded and involve a lot of typing. In reality it is quite quick and much may be copied and pasted. Once written and known to work then the expressions can be made into a function so any, similar, tank can be designed purely by typing the function name and adding the geometric and material parameters.

CITE THIS NOTEBOOK

Using finite elements to analyse structures in Mathematica​
by Malcolm Woodruff​
Wolfram Community, STAFF PICKS, February 20, 2026
​https://community.wolfram.com/groups/-/m/t/3642086