Understanding Tresca and von Mises Elastic Failure Theories
![[object Object]](/_next/image?url=%2Fimages%2Fauthors%2Fjulian_haudek.jpg&w=256&q=75)
As engineers, we see the term von Mises in pretty much every analysis software we open up, and I bet there are quite a few engineers out there who don’t fully understand what exactly it refers to…well, after completing this tutorial, you definitely won’t be one of them!
In this tutorial, Julian Haudek provides an excellent A-Z of Tresca and von Mises elastic failure theories. Here’s a breakdown...
Tutorial breakdown
📍 1.0 What does it mean for a material to fail?
We start by addressing a simple question: What is failure? Since our main focus is elastic failure theories, this is a logical place to get the brain warmed up!
📍 2.0 Recap of material strength fundamentals
We can’t understand Tresca and von Mises without understanding some fundamentals about how we model material behaviour. For most, this will be a review of familiar material. But, it will be helpful for those who haven’t picked up a mechanics of materials textbook in a while!
📍 3.0 Failure theories – turning complex stress into a simple answer
In section 3, we introduce the concept of a failure theory - it’s a simple idea but not one we’re routinely used to seeing…how this theory or that predicts structural failure. Again, this is essential groundwork for what follows.
📍 4.0 Tresca maximum shear stress failure theory
Now we can start to get to the heart of the issue - the failure theories themselves. We start by developing Tresca first, from the basic idea to a concise mathematical presentation of the theory…it’s not as difficult as it may sound!
📍 5.0 von Mises distortion energy failure theory
With Tresca covered and the understanding of what a failure theory actually is, now clear, working our way through von Mises is quite straightforward. Again, the aim is to balance theoretical development with an intuition for what von Mises stress actually is.
📍 6.0 Comparing Tresca and von Mises stress
A logical next step is to compare the two theories - that’s the aim of section 6. We’ll briefly outline the differences between the two and identify which one yields more conservative results!
📍 7.0 Worked Example – Putting the theory into action
As with any good engineering tutorial, it all starts to make much more sense when we plug some numbers into an example. In section 7, we’ll evaluate the equivalent Tresca and von Mises stresses in a relatively simple numerical example.
📍 8.0 Validation with Python’s sectionproperties
library
The calculations we completed in section 7 start to feel very tedious once you’ve done them a couple of times. So, in section 8, we introduce the open-source Python library, sectionproperties
. This allows us to dramatically speed up our geometric and stress analysis of the section. There’s no harm in using these tools…once we understand the underlying theory!
📍 9.0 Composite Section – Practical Use Case
In the previous section, we used sectionproperties
to validate the manual calculations we completed in section 7. This was a pretty simple problem and didn’t really push sectionproperties
too hard. So, in section 9, we tackle a more involved example…one that would be a real headache if we had to do it by hand!
📍 10.0 Final thoughts and wrapping up
Julian wraps things up in section 10 with some closing comments
I hope you enjoy the tutorial - please share this with anyone else you think might also find it helpful!
📂 Make sure to download the Jupyter Notebook (linked above) to run locally as you read through the tutorial.

1.0 What does it mean for a material to fail?
What does it actually mean when we say that a material has failed? Is it when it breaks apart? When it deforms permanently? Or simply when it no longer performs its intended function? The truth is failure isn't always visible or even obvious.
In reality, components develop complex, multi-axial stress states in response to external loading. Over time or under increasing load, these internal stresses can exceed the material’s capacity. Sometimes the component bends, sometimes it cracks and sometimes it simply deforms in a way that makes it unfit for purpose.
In this tutorial, we’ll introduce elastic failure theories which help us boil down complex stress states into a simple measure of how close a material is to failure. By the end you’ll understand the Tresca and von Mises failure theories and their application. We’ll work through some practical examples and even venture into some Python scripting to help speed up common stress analysis tasks.
2.0 Recap of material strength fundamentals
Before we discuss failure theories, let’s take a moment to quickly recap how we actually describe stress and strain in a solid body.
2.1 Stress at a point
At any point inside a loaded body, to fully describe the internal state of stress at that point, we isolate an infinitesimally small cube of the material and examine the stresses acting on each of its faces.
Each face of the infinitesimal cube can develop:
- one normal stress , acting perpendicular to the face,
- two orthogonal shear stresses , acting tangentially to the face.
This gives a total of 18 stress components for a 3-dimensional element (6 faces 3 stress components per face), Fig 1.

Fig 1. Stress components acting on an 3D infinitesimal cubic element.
However, it’s important to realise that not all of these components are independent,
- normal stresses on opposite faces have equal magnitudes,
- shear stresses also have equal magnitudes on opposing faces.
This symmetry of stress distribution is a direct consequence of the static equilibrium of the element. This means that only the stresses on 3 sides of the cube need to be considered - all others can be inferred from these. These symmetry conditions reduce the number of unique components from 18 to 9:
- 3 normal stresses: , ,
- 6 shear stresses: , ,
2.1.1 The stress tensor
These 9 components can be conveniently organised into a symmetrical stress tensor matrix:
The symmetry of this tensor arises from the condition of equilibrium, which ensures that:
As a result, only 6 independent components are needed to fully describe the stress state at a point.
This has important mathematical and physical consequences:
- The tensor is always diagonalisable,
- It always has real eigenvalues, which correspond to the principal stresses.
From this point onward, the stress tensor will serve as our main tool for describing 3D stress states.
2.1.2 Principal stresses
For any general 3D stress state, we can always find a coordinate system in which the stress tensor becomes diagonal - that is, all shear components vanish.
This system is aligned with the principal directions, and the diagonal entries of the transformed tensor are called the principal stresses:
where:
- – maximum principal stress,
- – intermediate principal stress,
- – minimum principal stress.
These principal stresses are the eigenvalues of the stress tensor. They represent the pure normal stresses acting on mutually orthogonal planes, with no shear.
This concept will be essential later, when we move on to failure theories. But before that, we’ll look at the counterpart of the stress tensor - the strain tensor, which describes how the material deforms under load.
2.2 Strain
When a body is subjected to external loading, we can think of each individual infinitesimal element changing its shape and dimensions. This deformation is described by the strain tensor, which is the geometric counterpart to the stress tensor. It’s the accumulation of these strains that we register as deformation of the structure.
2.2.1 Components of strain
When a material element is subjected to external loading, internal stresses develop in response and it undergoes deformation. This deformation can be separated into two fundamental types:
- Normal (volumetric) strain - change in length along the , , and directions, caused by normal stresses,
- Shear (distortional) strain - change in angles between the faces of the element, caused by shear stresses.
Each infinitesimal cube in the material can:
- stretch or compress in the three coordinate directions,
- experience angular distortion in the three orthogonal planes.
This gives us six independent strain components:
- Normal strains: , ,
- Shear strains: , ,
Together, they define the 3D state of strain in the material.

Fig 2. Deformed infinitesimal cube under 3D strain.
2.2.2 The strain tensor
Just as we can represent the state of stress at a point using the stress tensor, we can represent the corresponding strains with the strain tensor which captures deformation at a point under load. It contains all six independent components of strain: three normal and three shear.
In engineering, we typically describe shear using engineering shear strains , which represent the total change in angle between originally orthogonal edges. However, in tensor notation, shear strain components represent half of this angular change - hence the division by 2 in the strain tensor below.
The full 3D strain tensor is written as:
where:
- , , are the normal strains in each direction,
- , , are the shear strains.
Like the stress tensor, the strain tensor is symmetric, and its diagonalisation leads to the principal strains.
2.2.3 Strain energy
When a material element is deformed under load, it doesn't just change shape - it also stores energy internally, as long as the deformation remains elastic. This stored energy is called strain energy, and it's a direct result of the internal stresses and corresponding strains.
At each point in the material, part of the work done by external forces is absorbed and retained as internal energy - this energy is fully recoverable if the material unloads without yielding.
In all cases, strain energy depends on:
- the magnitude of the internal force or moment,
- the material stiffness,
- and the section geometry
The concept of strain energy is fundamental not just in deformation analysis, but also in defining failure criteria like the von Mises yield criterion, which is based on the idea of distortion energy stored in the material. I briefly introduce strain energy here as it naturally follows from a discussion of strain, but we’ll return to this concept and discuss it in more detail later in the tutorial!
3. Failure theories – turning complex stress into a simple answer
In structural design, we’re making decisions about whether a material will withstand the loads it's subjected to. That boils down to a simple but fundamental question:
Are the internal stresses low enough for the material to maintain structural integrity?
This brings us to the concept of utilisation - a scalar quantity that tells us how much of the material’s capacity is being used at a given point. In other words, it measures how close we are to a critical state, where failure might occur. We can define the utilisation or degree of utilisation as a dimensionless ratio, ,
where:
- is the design resistance, obtained from the characteristic strength divided by the material safety factor .
- is a measure of the state of stress in the material. The subscript indicates that this stress is a single value that has been determined by reducing the more complex stress state (captured in the stress tensor) into a single value.
The value of depends on the elastic failure theory adopted (more on this later). In broad terms, we can define it as some function of the elements of the stress tensor at a given point in the loaded structure,
The utilisation ratio is defined such that when:
- the structure can be considered safe
- the structure can be considered at the limit of safety
- structural failure is possible and the structure is unsafe.
The value of is a function of the particular failure theory we adopt. Remember, it is a value of stress obtained by boiling down the stress tensor into a single value. The basis upon which we do this reduction is governed by the adopted failure theory.
A failure theory is a simplified model of how materials fail under complex, multi-axial loading. In real structures, stress states are rarely simple. At any point in the structure, typically, a combination of normal and shear stresses develop. These act on different planes and in different directions.
However, material tests and material strength data are usually based on uniaxial tension. So, we need a way to relate complex stress states to simple test data. This is exactly what failure theories do - they defines a rule;
This stress state is equivalent to that uniaxial one.
In other words, they allow us to reduce a 3D multi-axial stress state to an equivalent uniaxial one with approximately the same internal effect and degree of utilisation. Once this reduced stress is calculated, it can be directly compared to the design resistance of the material, just like in a simple tensile test.
3.1 Types of failure theories
Different theories make different assumptions about what actually causes failure in a material. Here’s a quick overview of the classical criteria:
-
Galilei Theory - assumes failure occurs when normal stress in any direction reaches the tensile strength.
-
Rankine Theory - failure occurs when the maximum principal normal stress exceeds the material limit.
-
Saint-Venant Theory - assumes failure occurs when the maximum normal strain exceeds a critical value.
-
Guest-Tresca Theory - failure is caused by maximum shear stress reaching a critical value.
-
von Mises (H. Hencky) Theory - failure depends on distortion energy in the material.
Each of these theories defines a different formula for the function and therefore leads to different values of - and different predictions of when failure will occur.
In this tutorial, we’ll focus on the two most important theories for ductile materials:
- Tresca – simple, conservative, based on shear
- von Mises – widely used in practice, based on distortion energy
Over the next two sections, we’ll break them down and see how they work.
4.0 Tresca maximum shear stress failure theory
The Tresca failure theory, also known as the maximum shear stress theory, is one of the earliest and most widely known failure criteria for ductile materials. It is based on the idea that yielding in a material starts when the maximum shear stress at a point reaches a critical value equal to the maximum shear stress at failure in simple tension.
Historically, this criterion is attributed to the French engineer Henri Tresca (circa 1864), but it is closely related to earlier ideas proposed by Coulomb (for friction and cohesion in soils) and Guest (1864), who applied the maximum shear stress idea to metals.
Tresca failure is based on a simple assumption:
Failure will occur when the maximum shear stress in the material is equal to the maximum shear stress at failure in simple tension.
In uniaxial tension, the principal stresses are:
So the maximum shear stress is:
Thus, Tresca's yield condition becomes:
or equivalently:
where:
- are the principal stresses, ordered so that .
Yielding occurs when the difference between the largest and smallest principal stress reaches the yield stress in simple tension.
The fact that the maximum shear stress depends only on the difference between and comes directly from the geometry of Mohr's circle - where this difference defines the diameter, and the radius corresponds to .
We can define the reduced stress for Tresca as:
so the utilisation becomes:
-
The Tresca criterion is conservative compared to von Mises - it predicts yielding sooner.
-
It is simple and intuitive, especially when shear dominates
-
It ignores the intermediate principal stress , which may be significant in triaxial stress states.
-
Tresca is still used in manual design and hand calculations due to its simplicity.
5.0 von Mises distortion energy failure theory
The von Mises theory, also known as the maximum distortion energy theory, is one of the most widely used strength criteria for ductile materials. It is based on the idea that yielding begins when the distortion energy per unit volume reaches the same value as in a uniaxial tensile test at yield.
Although commonly named after Richard von Mises (1913), the theory was developed independently by Heinrich Hencky (1924). Earlier developments are credited to Tadeusz Huber (1904). For this reason, it is often referred to as the Huber–von Mises-Hencky theory.
When a material deforms, the internal strain energy can be split into two parts:
- Volumetric energy - associated with change in volume (hydrostatic part),
- Distortion energy - associated with change in shape (deviatoric part).
The von Mises theory assumes that yielding occurs when the distortion energy reaches a critical value:
Yielding starts when the distortion energy in a general stress state equals that in a uniaxial tensile test at yield.
This makes the von Mises criterion insensitive to hydrostatic pressure, which agrees well with experimental results for metals - they do not yield under pure pressure.
The von Mises criterion is based on the idea that yielding begins when the distortion energy per unit volume reaches the same value as in a uniaxial tensile test at yield. In a general 3D stress state, the distortion energy is defined as:
In a uniaxial tension test (only , others are zero), this becomes:
Equating these two gives us the von Mises yield condition:
5.1 Equivalent (von Mises) stress
Based on the above, we define the equivalent (or reduced) stress as
For the plane stress case (), the formula simplifies to:
We can restate the reduced stress is terms of the components of the stress tensor as follows,
Note that the von Mises formulation results directly from the assumption that plastic flow starts when the distortion energy exceeds the elastic limit. It's an energy-based criterion, unlike Tresca which is purely stress-based.
5.2 Why von Mises works
-
Experimental results show that ductile metals tend to yield when distortion energy reaches a threshold - not when maximum stress or strain is reached.
-
The von Mises criterion matches this observation well and is supported by plasticity theory.
-
It is differentiable and smooth, making it ideal for numerical methods (like FEA).
-
It consistently provides more accurate and less conservative results than Tresca, especially in complex loading.
-
von Mises includes the effects of all six stress components - both normal and shear.
-
It is the default criterion in most structural and FEA software.
-
Unlike Tresca, it cannot be directly interpreted as a "maximum" stress; it is energy-based.
In the next section, we’ll compare the Tresca and von Mises criteria side by side, and visualise their yield surfaces.
6.0 Comparing Tresca and von Mises stress
To better understand how the Tresca and von Mises criteria relate to each other, let’s look at them from a geometric perspective. We can reduce the complexity of the discussion but still maintain the core ideas by reducing from a triaxial to a plane stress condition. This simply means setting the following stress components to zero,
As a result, we’re left with three stress components:
- – normal stress in x-direction,
- – normal stress in y-direction,
- – shear stress in the xy-plane.
Each failure theory defines a yield locus in this 2D stress space - a closed curve around the origin that separates “safe” from “failed” stress states.
6.1 von Mises (plane stress case)
The von Mises equivalent stress under plane stress conditions () is:
The resulting yield surface is smooth - it forms an ellipse (or a circle in the principal stress space). It’s often described as the least conservative criterion, because it allows slightly higher stress states before predicting yielding.
6.2 Tresca (plane stress case)
For Tresca, the equivalent stress under plane stress is:
This results in a hexagon in stress space - with sharp corners corresponding to sudden yielding. Tresca is more conservative than von Mises and predicts failure earlier in some stress states.
Now, let’s visualise both yield criteria in the – plane (assuming ). We’ll use some simple Python plotting to show how each criterion defines the boundary between safe and unsafe stress states.
We can start by importing some basic dependencies and defining a range of normal stress values around an arbitrary value of yield stress. We then use Numpy’s meshgrid()
method to convert these value ranges into a set of 2D coordinate pairs in the – plane.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
# Yield stress (arbitrary value)
sigma_y = 1.0
# 2D grid
s1 = np.linspace(-1.5 * sigma_y, 1.5 * sigma_y, 500)
s2 = np.linspace(-1.5 * sigma_y, 1.5 * sigma_y, 500)
S1, S2 = np.meshgrid(s1, s2)
Then we define the von Mises and Tresca failure criterion. In each case, we will end up with a value of the failure criterion for every grid point on the 2D plane. We are interested in the boundary, where the failure criterion goes from a negative (safe) to positive (unsafe). This boundary is referred to as a yield locus.
# von Mises criterion
vm = np.sqrt(S1**2 - S1*S2 + S2**2) - sigma_y
# Tresca criterion
t1 = np.abs(S1 - S2)
t2 = np.abs(S1)
t3 = np.abs(S2)
tresca = np.maximum.reduce([t1, t2, t3]) - sigma_y
We can visualise the yield locus using a contour plot in which we only visualise a single contour (at level ) for each criterion.
# Plot
plt.figure(figsize=(8, 8))
plt.contour(S1, S2, vm, levels=[0], colors='blue', linewidths=2)
plt.contour(S1, S2, tresca, levels=[0], colors='red', linewidths=2)
# Labels
plt.xlabel(r'$\sigma_1$')
plt.ylabel(r'$\sigma_2$')
plt.title('Yield Surfaces: von Mises (blue) vs. Tresca (red)')
plt.grid(True)
plt.axis('equal')
# Legend
legend_elements = [
Line2D([0], [0], color='blue', lw=2, label='von Mises'),
Line2D([0], [0], color='red', lw=2, label='Tresca')
]
plt.legend(handles=legend_elements)
plt.show()

Fig 3. Yield locus for Tresca (red) and von Mises (blue) failure criterion.
The area contained within each yield locus defined the safe region based on each failure criterion. Remember, the state of stress for a given element corresponds to a location on this 2D plane. So the yield locus is a helpful way of interpreting the relationship between any stress state and its proximity to failure.
We can also clearly see why Tresca is considered more conservative than von Mises, since it will predict failure for certain stress states that are still within a von Mises safe region.
Remember, in this discussion we have assumed plane stress with zero shear stress - a valid yet simplified stress state. Nevertheless, the fundamental points remain unchanged when moving to more complex stress states.
7.0. Worked Example – Putting the theory into action
To demonstrate the practical application of everything we’ve discussed so far, we’ll analyse a simple beam subjected to transverse bending. This loading will lead to a combined stress state — ideal for applying the Tresca and von Mises criteria.
Consider the beam shown in Fig 4. below. Our goal is to compute the reduced stress in selected cross-sections.

Fig 4. Beam subject to transverse and axial loading.
7.1 Reactions, shear, axial and moment diagrams
Before we begin the stress analysis, we’ll summarise the support reactions, shear force diagram, bending moment diagram and axial force diagram, Fig 5. Since this is a simple statically determinate beam we won’t spend time here on how these diagrams are constructed (see our Ultimate Guide to Shear Force and Bending Moment Diagrams if you need more help with this).

Fig 5. From top to bottom, reactions diagram, shear force diagram, bending moment diagram and axial force diagram.
7.2 Geometry of the cross-section
To perform stress analysis, we first need to define the cross-section of our beam. In this example, we consider a welded I-beam or plate girder - a symmetric section composed of:
- two horizontal flanges (top and bottom),
- and a vertical web in between.
This type of section is widely used in engineering due to its high bending efficiency. The exact dimensions are shown in Fig. 6.

Fig 6. Cross-section geometry.
We will analyse the cross-section at support B, where both the bending moment and the shear force reach their maximum values. This is the most critical section in terms of internal forces, making it the best candidate for evaluating potential failure.
7.3. Shear stress
We now calculate the shear stress in the section using the transverse shear force .
In I-sections, the shear stress has a parabolic distribution within each region, but the function is discontinuous at the transition between flange and web. It’s nearly zero in the flanges, and significantly concentrated in the web, where the reduced width results in higher shear stress values.
We apply the general shear formula:
where:
- (moment of inertia for the section)
- – first moment of area above point
- – local width at that point
We compute the shear stress in 5 characteristic locations:
Point 1 – Top flange (extreme fiber)
Point 2 – Flange–web junction
Point 3 – Web just below flange
- (same )
-
Point 4 – Mid-height of web (centroid)
Point 5 – bottom flange (extreme fiber)
7.3.1 Summary Table:
Location | [mm] | [mm] | [mm³] | [MPa] |
---|---|---|---|---|
Top flange (extreme) | +90 | 85 | 0 | 0 |
Flange–web junction | +80 | 85 | 72250 | 2.31 |
Web just below flange | +80 | 7 | 72250 | 28.10 |
Mid-height of web (centroid) | ±0 | 7 | 94650 | 36.82 |
Web just below flange | -80 | 7 | 72250 | 28.10 |
Flange–web junction | -80 | 85 | 72250 | 2.31 |
Bottom flange (extreme) | -90 | 85 | 0 | 0 |
So we observe:
- The maximum shear stress occurs in the center of the web, where both and are largest.
- Shear stress is zero in the outer flanges, and low at the web-flange junction when is large.

Fig 7. Shear stress distribution.
7.4 Normal Stress
The normal stress in the beam comes from two internal effects:
- Axial force (uniform across the section)
- Bending moment (linearly distributed across the height)
We analyse both effects separately below.
7.4.1 Axial stress due to axial force
The axial force , produces a uniform normal stress across the cross-section:
where the area of the cross section, is easily computed,
With an axial load of , we have an axial stress of,

Fig 8. Axial stress distribution.
7.4.2 Normal stress due to moment
The bending moment produces a linearly varying normal stress distribution, which changes with vertical position in the cross-section. In our beam, the top fibers are under tension, and the bottom fibers are compressed. This is because the moment opens the section upwards.
We use the bending stress formula:
where:
- – vertical coordinate from the neutral axis (positive upwards)
We evaluate in the same 5 characteristic locations across the section height:
Location | [mm] | [m] | [MPa] |
---|---|---|---|
Top flange (extreme fiber) | |||
Top web–flange junction | |||
Neutral axis (centroid) | |||
Bottom web–flange junction | |||
Bottom flange (extreme fiber) |
So in Fig. 9 we see the stress varies linearly from tension at the top to compression at the bottom.

Fig 9. Normal stress distribution due to bending.
We can now combine the two components of normal stress:
- Axial stress – uniform over the cross-section
- Bending stress – linear across the height
The total normal stress at each point is simply:
This gives us the full distribution of across the section:
Location | [mm] | [MPa] |
---|---|---|
Top flange (extreme fiber) | ||
Top web–flange junction | ||
Neutral axis (centroid) | ||
Bottom web–flange junction | ||
Bottom flange (extreme fiber) |

Fig 10. Combined normal stress from axial force and bending moment.
7.5 Equivalent Stress – Failure Theories
To assess the combined effect of normal stress and shear stress , we can employ our two failure theories, von Mises (Huber–Hencky) and Tresca (Guest).
In our case of transverse bending, the relevant stress state has only:
All other components are reasonably assumed to be zero:
7.5.1 von Mises theory
For 2D stress state , the reduced stress becomes,
This expression is derived from the general 3D form we saw earlier,
7.5.2 Tresca theory
The reduced stress based on Tresca theory is given by
For plane stress , principal stresses are,
Thus, the maximum difference:
So, we arrive at the Tresca equivalent stress,
These expressions allow us to compute the equivalent uniaxial stress at any point in the cross-section, and compare it directly to the material yield limit.
By combining the calculated stresses with Tresca and von Mises expressions, we can summarise the equivalent uniaxial stresses - the values are tabulated below
Location | [mm] | [MPa] | [MPa] | [MPa] | [MPa] |
---|---|---|---|---|---|
Top flange (extreme) | +90 | +248.61 | 0.00 | 248.61 | 248.61 |
Flange–web junction (top) | +80 | +221.39 | 2.31 | 221.43 | 221.44 |
Web just below flange (top) | +80 | +221.39 | 28.10 | 226.68 | 228.41 |
Web center (neutral axis) | 0 | +3.55 | 36.82 | 63.87 | 73.73 |
Web just below flange (bottom) | -80 | -214.29 | 28.10 | 219.75 | 221.54 |
Flange–web junction (bottom) | -80 | -214.29 | 2.31 | 214.33 | 214.34 |
Bottom flange (extreme) | -90 | -241.51 | 0.00 | 241.51 | 241.51 |
As expected:
- Maximum equivalent stress occurs in the flanges, where normal stress is greater.
- Tresca gives consistently higher (more conservative) values than von Mises.

Fig 11. Reduced Tresca and vom Mises stresses.
These values are ready to be compared with material limits to assess safety. In practice, the admissible stress would depend on the steel grade used but this is not our focus here. Instead, we’ll proceed to verify our results.
8.0 Validation with Python’s sectionproperties
library
To wrap up our manual calculations from the previous section, we turn to a powerful tool that can help us perform the same analysis much quicker - the open source Python library sectionproperties
. You may have come across sectionproperties
in these previous EngineeringSkills tutorials:
- Reinforced Concrete Column Design to ACI 318-14 with Python and concreteproperties
- A Pynite Crash Course - Open Source Finite Element Modelling for Structural Engineers
This library is highly flexible, allowing us to analyse cross-sections and perform geometric and stress analysis. It’s particularly suited for civil and structural engineering applications.
Make sure to read through the official
documentation when you
want to start using sectionproperties
in your own projects.
8.1 What does sectionproperties
do?
In summary, the library allows you to:
-
Define custom cross-sections using basic or composite shapes
-
Assign materials to individual parts of a geometry (including multi-material composites)
-
Compute geometric properties of the cross-section such as,
- area, centroids, second moments of area (, ),
- principal axes, torsion constants, warping parameters, etc.
-
Perform stress analysis based on applied loads e.g. axial force, bending moments, shear forces, torsion.
-
Visualise results as stress contour plots or stress vectors
8.2 Validating our analytical results
In this part, we’ll use sectionproperties
to verify the results we manually calculated in the previous section. We’ll recreate the same I-beam geometry, apply the same loads, and compare the stress values.
Start by pip installing section properties into your development environment. It’s available directly from the Python Package Index (PyPI):
pip install sectionproperties
Next, we’ll import only the parts of the library that we actually need.
from sectionproperties.pre.library import i_section
from sectionproperties.analysis import Section
The modular structure of sectionproperties
allows us to keep things lean by importing only the specific classes and tools we need. In our case, i_section
helps us define a standard I-beam, and Section
is the main class we’ll use for analysis.
8.2.1 Defining the cross-section geometry
We can now define the geometry of our I-beam using a built-in helper function:
geometry = i_section(d=180, b=85, t_f=10, t_w=7, r=0, n_r=0)
The sectionproperties
library makes it very convenient to define standard sections through predefined functions like i_section()
. We could build the I-beam manually from three separate rectangles (two flanges and one web), but using the built-in constructor is simpler and more readable.
The parameters we use here are:
d = 180
→ total section height [mm]b = 85
→ flange width [mm]t_f = 10
→ flange thickness [mm]t_w = 7
→ web thickness [mm]r = 0
→ fillet radius at the flange-web junction (set to zero in our case)n_r = 0
→ number of elements used to discretise the fillet arc (also zero, since we have no fillet)
These values match the dimensions specified in Fig 6. Setting r=0
and n_r=0
means we’re working with a purely rectangular shape, without any rounding between web and flanges which simplifies both modelling and comparison with our hand calculations.
8.2.2 Meshing the geometry
Once the geometry is defined, we need to generate a finite element mesh for analysis.
geometry.create_mesh(mesh_sizes=5)
This step discretises the cross-section into triangular finite elements, which are used to perform the stress calculations later on. The argument mesh_sizes=5
sets the approximate size of the mesh elements. Smaller values give a finer mesh and more accurate results - at the cost of longer computation time.
In our case, a mesh size of provides a good balance between speed and precision. Now we can plot our shape using:
geometry.plot_geometry()

Fig 12. Cross-section geometry model.
8.3.3 Creating the Section and running the analysis
Once the geometry is defined and meshed, we wrap it in a Section
object, which gives us access to all of the analysis methods.
section = Section(geometry)
We then calculate the cross-sectional properties:
-
section.calculate_geometric_properties()
computes standard values like area, centroid, and moments of inertia. -
section.calculate_warping_properties()
adds advanced properties related to torsion and warping.
section.calculate_geometric_properties()
section.calculate_warping_properties()
Finally, we run the actual stress analysis by applying internal forces:
stress = section.calculate_stress(n=10e3, mxx=-40e6, vy=-40e3)
This applies:
- a normal force ,
- a bending moment ,
- and a shear force
The loads are the same as in our earlier manual example, but the coordinate system used by sectionproperties
is different:
- In our manual calculations:
- is the beam axis (length),
- is horizontal,
- is vertical (height of the section)
- In
sectionproperties
:- is the beam axis (length),
- is horizontal (left–right),
- is vertical (upward)
So the moment about the horizontal axis of bending is now called mxx
, and the shear force in vertical direction becomes vy
.
Also note that the units are in N and N·mm, so we need to scale our loads accordingly:
This ensures consistency with the internal units used by sectionproperties
, which work in mm, N, and MPa.
8.3.4 Plotting stress distributions
That’s it - we’ve got the geometry, loads, and now it’s time to visualise the results! We can use plot_stress()
to display stress contours over the cross-section:
# Normal stress due to axial force N
stress.plot_stress(stress="n_zz", title=r"$\sigma_{N}$ – Normal Stress from Axial Force $N$")
# Normal stress due to bending moment Mxx
stress.plot_stress(stress="mxx_zz", title=r"$\sigma_{M}$ – Normal Stress from Bending Moment $M_{xx}$")
# Combined normal stress (axial + bending)
stress.plot_stress(stress="zz", title=r"$\sigma_{x}$ – Combined Normal Stress (Axial + Bending)")
# Shear stress due to transverse force Vy
stress.plot_stress(stress="vy_zy", title=r"$\tau_{xz}$ – Shear Stress from Transverse Force $V_{y}$")

Fig 13. Various stress distributions, calculated by sectionproperties
.
Fig 13 above shows how the stress is distributed across the section based on the specified internal force. This confirms what we saw in our manual calculations: uniform axial stress, linear bending stress and parabolic shear.
Figure 14 below shows that the numerical values also match very closely with our analytical results – this gives us confidence that our hand calculations were correct.

Fig 14. Comparison between analytically and numerically calculated stresses.
Note that in the contour plots in Fig 13 and 14, the coloured bar on the right is a legend, not a side view of stress distribution.
8.3.5 Calculating Tresca and von Mises stress
Once we’ve got the individual stress components, the next logical step is to compute the reduced (equivalent) stress - the Tresca and von Mises stress.
The von Mises stress is already built into sectionproperties
- so it can be calculated immediately.
stress.plot_stress(stress="vm", title=r"$\sigma_{\text{red}}$ – Equivalent Stress von Mises")

Fig 15. Equivalent von Mises stress.
The calculation of the Tresca stress is slightly more involved. The library does not currently include native support for the Tresca theory, so if we want to visualise it, we need to compute it manually. Here’s how we can do that.
stress_data = stress.get_stress()[0]
sigma = stress_data["sig_zz"] # normal stress [<class 'numpy.ndarray'>]
tau = stress_data["sig_zy_vy"] # shear stress [<class 'numpy.ndarray'>]
# Equivalent stress using the 2D Tresca formula
sigma_tresca = np.sqrt(sigma**2 + 4 * tau**2) # [<class 'numpy.ndarray'>]
# Overwrite the default von Mises field with our manually computed Tresca values
stress.material_groups[0].stress_result.sig_vm = sigma_tresca
# Reuse the same plotting method to show our custom result
stress.plot_stress(stress="vm", title=r"$\sigma_{\text{red}}$ – Equivalent Stress Tresca")

Fig 16. Equivalent Tresca stress.
This method leverages the internal structure of the StressPost
object to temporarily replace the von Mises result with our own custom field. It’s not the most elegant solution, but it allows us to use all the built-in visualisation tools without having to create custom plotting routines from scratch. Let's take a look at the comparison.

Fig 17. Equivalent von Mises and Tresca stress comparison.
With this, we’ve completed the full validation of our analytical example using sectionproperties
. The stress distributions obtained numerically, including axial, bending, shear, and equivalent stresses, match the manual results presented earlier. This confirms that both our theoretical approach and the numerical tool are consistent, and that sectionproperties
can be used confidently for practical stress analysis in structural sections.
9.0 Composite Section – Practical Use Case
To showcase the more advanced capabilities of sectionproperties
, let’s consider a slightly more challenging engineering scenario. We'll model a composite structural system consisting of:
- a tapered flange I-beam (steel),
- a channel section welded on top of the I-section (also steel),
- and a concrete compression block on top.
This steel-concrete composite floor beam is a great example of how sectionproperties
can handle composite geometries, different materials, and complex loading. It would also be very laborious to tackle by hand!
Since we’ve already covered the basics in the previous example, we won’t go through the code line by line. What’s new here is the definition of material properties and more advanced geometry manipulation, both of which are fairly self-explanatory. For further details, feel free to consult the official documentation. Here’s the Python code that builds the model and runs the stress analysis:
from sectionproperties.pre import Material
from sectionproperties.pre.library import tapered_flange_i_section, channel_section, rectangular_section
# Material definitions
steel = Material(
name="Steel",
elastic_modulus=200e3,
poissons_ratio=0.3,
yield_strength=355,
density=7.85e-6,
color="grey"
)
concrete = Material(
name="Concrete",
elastic_modulus=30e3,
poissons_ratio=0.2,
yield_strength=20,
density=2.4e-6,
color="lightgrey"
)
# Define steel element geometries
beam = tapered_flange_i_section(d=114, b=76, t_f=8.2, t_w=4.4, r_r=9, r_f=3, n_r=9, alpha = 10, material=steel)
c_section = channel_section(d=100, b=50, t_f=8.5, t_w=5, r=9, n_r=9, material=steel)
c_section = c_section.rotate_section(angle=90)
c_section = c_section.align_center(align_to=beam).align_to(other=beam, on="top")
# Define concrete block 200x300 mm
block = rectangular_section(d=300, b=200, material=concrete)
block = block.align_center(align_to=beam).align_to(other=beam, on="top")
# Combine all parts into a single geometry
geometry = beam + c_section + block
# Mesh the geometry
geometry.create_mesh(mesh_sizes=[5, 5, 30])
section = Section(geometry=geometry)
section.plot_mesh()

Fig 18. Finite element mesh generated by sectionproperties
.
# Perform geometric analysis
section.calculate_geometric_properties()
section.calculate_warping_properties()
# Define actions on the section and perform stress analysis
stress = section.calculate_stress(
n=20e3,
mxx=80e6,
myy=30e6,
vx=10e3,
vy=-20e3,
)
# Plot von Mises stress
stress.plot_stress(stress="vm", title=r"$\sigma_{\text{red}}$ – Equivalent Stress von Mises")

Fig 19. Equivalent von Mises stress calculated by sectionproperties
.
Since this setup is difficult to verify analytically, I created the same model in Autodesk Robot Structural Analysis and applied the same internal forces. The comparison of von Mises stress distributions is shown below:

Fig 20. Comparison of von Mises stress in sectionproperties
(right) and
Autodesk Robot (left).
We observe very good agreement between the two tools:
- The stress pattern is consistent in both models.
- Maximum stress appears in the bottom right flange of the I-beam - just as expected from combined axial load and bending.
- Near the neutral axis, stress drops off significantly, matching theory.
Quantitatively, the peak von Mises stress:
- 157.25 MPa in
sectionproperties
- 164.24 MPa in Robot
This results in a relative difference of just ~4.3%, which is acceptable for this type of numerical model comparison. We could seek to reduce this disparity further by tweaking both models and exploring the influence of mesh density, for example. However, sufficient agreement is demonstrated to be comfortable that we’ve correctly modelled the composite beam.
9.1 Conclusion
This final example highlights that sectionproperties
is a powerful engine for practical structural modelling:
- easily combining multiple shapes and materials,
- handling custom geometries and load states,
- offering mesh control, visualisation, and stress post-processing.
Whether you're teaching mechanics, scripting design checks, or verifying cross-section behaviour in research - this tool is an excellent addition to any engineer’s toolkit.
10.0 Final thoughts and wrapping up
In this tutorial, we’ve covered:
- a recap of the fundamentals of strength of material,
- an introduction to elastic failure theories, and the development of Tresca and von Mises failure criterion,
- a demonstration of how we can calculate Tresca and von Mises stress, based on structural loading,
- a demonstration of how we can speed up our analysis using the open-source library,
sectionproperties
.
Our aim with this tutorial was not simply to show you how to use sectionproperties
to do the analysis for you but to help you understand the theory behind the analysis being performed. Only by understanding the underpinning theory can you truly have confidence in what’s being reported back to you!
I hope you’ve enjoyed this tutorial and found it helpful. I’ll be back with another one soon - see you then!
Featured Tutorials and Guides
If you found this tutorial helpful, you might enjoy some of these other tutorials.
P-Delta Analysis and Geometric Non-linearity
In this tutorial, we'll explore P-Delta analysis, a geometric non-linearity that can lead to large deflections in slender structures

Dr Seán Carroll
Structural Analysis Case Study
How the structural analysis process works for a real-world structure

Dr Seán Carroll
Getting Started with Graphic Statics
Rediscover the link between geometry and load flow with graphical structural analysis techniques.

Prof Edmond Saliklis