Stress

The components of stress at a point are the forces per unit area acting on planes passing through the points. The tensor notation, or Einstein notation for stress is $\sigma_{ij}$ where $i,j=1,3,4$. The first index corresponds to the direction of the normal to the plane of interest and the second index corresponds to the direction of the force as illustrated in Figure-1 (left).

Figure-1: Components of stress in a 1,2,3 koordinate system

The stress tensor can be written as a 3 x 3 matrix:

\begin{equation} \boldsymbol{\sigma}= \begin{bmatrix} \sigma_{11} & \sigma_{21} & \sigma_{31} \\ \sigma_{12} & \sigma_{22} & \sigma_{32} \\ \sigma_{13} & \sigma_{23} & \sigma_{33} \end{bmatrix} \label{eq:stresstensor1} \tag{1} \end{equation}

Force and moment equilibrium requires that the stress tensor to be symmetric (i.e., $\sigma_{ij}=\sigma_{ji}$). Furthmore, we will follow the common practice to use the notation $\tau_{ij}$ for shear stresses and use reduced notation for normal stresses (i.e., $\sigma_{ii}=\sigma_i$). Hence, the stresses by the simplified matrix notation becomes

\begin{equation} \boldsymbol{\sigma}= \begin{bmatrix} \sigma_{1} & \tau_{12} & \tau_{13} \\ \tau_{12} & \sigma_{2} & \tau_{23} \\ \tau_{13} & \tau_{23} & \sigma_{3} \end{bmatrix} \label{eq:stresstensor2} \tag{2} \end{equation}

Due to the symmetry, there are only 6 independent components of stress.

In a coordinate system x,y,z as illustrated in Figure-2, the stress is written

\begin{equation} \boldsymbol{\sigma}= \begin{bmatrix} \sigma_{x} & \tau_{xy} & \tau_{xz} \\ \tau_{xy} & \sigma_{y} & \tau_{yz} \\ \tau_{xz} & \tau_{yz} & \sigma_{z} \end{bmatrix} \label{eq:stresstensor3} \tag{3} \end{equation}

Figure-2: Components of stress in a x,y,z coordinate system

If the concept of stress somehow gone under the radar during your materials and mechanical engineering studies, an introductory textbook on mechanics of materials, for example [1] will provide the proper background

Consider a stress state

$$ \boldsymbol{\sigma}= \begin{bmatrix} \sigma_{x} & \tau_{xy} & \tau_{xz} \\ \tau_{xy} & \sigma_{y} & \tau_{yz} \\ \tau_{xz} & \tau_{yz} & \sigma_{z} \end{bmatrix}= \begin{bmatrix} 100 & 20 & 0 \\ 20 & 50 & 0 \\ 0 & 0 & 0 \end{bmatrix} $$

A straight forward NumPy-array representation is:

In [1]:
import numpy as np

sigA=np.array ( [ [  100.0,  20.0,   0.0   ],
                  [     20.0,  50.0,   0.0 ],
                  [      0.0,   0.0,   0.0 ] ])

print(sigA)
[[100.  20.   0.]
 [ 20.  50.   0.]
 [  0.   0.   0.]]

The stress state above is an example of a plane stress case (stress exsists only on the 1-2 plane), while the two examples that follow are pure shear ($\tau_{yz} \ne 0$) and pure pressure ($\sigma_x=\sigma_y=\sigma_z=-P$) respectively:

In [2]:
sigB=np.array ( [ [ 0.0,   0.0,   0.0 ],
                  [ 0.0,   0.0,  50.0 ],
                  [ 0.0,  50.0,   0.0 ] ] )

sigC=np.array ( [ [-20.0,   0.0,  0.0 ],
                  [  0.0, -20.0,   0.0 ],
                  [  0.0,   0.0, -20.0 ] ] )

print(sigB)
print()
print(sigC)
[[ 0.  0.  0.]
 [ 0.  0. 50.]
 [ 0. 50.  0.]]

[[-20.   0.   0.]
 [  0. -20.   0.]
 [  0.   0. -20.]]

Eigenvalues and eigenvectors

The eigenvalues $\lambda$ and the eigenvectors $\mathbf{v}$ are the solutions of \begin{equation} (\boldsymbol{\sigma}-\mathbf{I}\lambda)\mathbf{v}=\mathbf{0} \label{eq:eigenv} \tag{4} \end{equation}

Plane stress example where $\sigma_z=\tau_{xz}=\tau_{yz}=0$ :

In [3]:
sig=np.array ( [ [ 100.0,  20.0,  0.0 ],
                 [  20.0,  50.0,  0.0 ],
                 [   0.0,   0.0,  0.0 ] ] )

L,v = np.linalg.eig(sig)

print('Eigenvalues:')
print(L)
print()
print('Eigenvectors:')
print(v)
Eigenvalues:
[107.01562119  42.98437881   0.        ]

Eigenvectors:
[[ 0.94362832 -0.33100694  0.        ]
 [ 0.33100694  0.94362832  0.        ]
 [ 0.          0.          1.        ]]

Note that the eigenvectors are the given by columns and thus it is more convenient to do a transpose:

In [4]:
v = v.T
for vi in v:
    print(np.round(vi,3))
[0.944 0.331 0.   ]
[-0.331  0.944  0.   ]
[0. 0. 1.]

Verify that equation (4) is true by computing \begin{equation} (\boldsymbol{\sigma}-\mathbf{I}\lambda)\mathbf{v} \tag{5} \end{equation}

In [5]:
I=np.identity(3)
print(np.round(np.dot((sig-I*L[0]),v[0]),3))
print()
print(np.round(np.dot((sig-I*L[1]),v[1]),3))
print()
print(np.round(np.dot((sig-I*L[2]),v[2]),3))
[0. 0. 0.]

[ 0. -0.  0.]

[0. 0. 0.]

Pincipal stresses

The 1st, 2nd and 3rd principal stresses are found among the eigenvalues, where the 1st is the max value and the 3rd is the min value. That is:

In [6]:
s_1st = max(L)
s_3rd = min(L)

print('First principal stress =  ',s_1st)
print('Third principal stress =  ',s_3rd)
First principal stress =   107.01562118716424
Third principal stress =   0.0

The directions and relative magnitude of the principal stresses in the x-y plane illustrated using the code from Plot gallery:

In [7]:
from plotlib import pristrxyplot
pristrxyplot(L,v)
No description has been provided for this image

The angle between the 1st principal stress and the $x$ -axis is:

In [8]:
from math import degrees, acos
angle=degrees(acos(v[0][0]))
print('{0:0.1f} degrees'.format(angle))
19.3 degrees
How are principal stresses useful in a lightweight design process? To be discussed in lectures.

Maximum shear stress

The maximum shear stress is \begin{equation} \tau_{max}=\frac{1}{2}(\sigma_{max}-\sigma_{min}) = \frac{1}{2}(\sigma_{1st}-\sigma_{3rd}) \tag{6} \end{equation}

In [9]:
tau_max = (1/2)*(s_1st - s_3rd)
print('Maximum shear stress:',tau_max)
Maximum shear stress: 53.50781059358212

Isostatic, deviatoric and von Mises stress

The isostatic stress tensor $\boldsymbol{\sigma_0}$ is \begin{equation} \boldsymbol{\sigma_0}=\frac{1}{3}\big(\sigma_x+\sigma_y+\sigma_z\big)\mathbf{I} \tag{7} \end{equation}

In [10]:
iso=(1/3)*np.trace(sig)*np.identity((3))
print('Isostatic stress:\n\n',iso)
Isostatic stress:

 [[50.  0.  0.]
 [ 0. 50.  0.]
 [ 0.  0. 50.]]

where the trace of $\boldsymbol{\sigma}$ is $\sigma_x+\sigma_y+\sigma_z$

In [11]:
print( np.trace(sig))
150.0

The deviatoric stress tensor, \begin{equation} \boldsymbol{\sigma_{dev}}=\boldsymbol{\sigma}-\boldsymbol{\sigma_0} \tag{8} \end{equation}

In [12]:
sdev=sig-iso
print('Deviatoric stress:\n\n',sdev)
Deviatoric stress:

 [[ 50.  20.   0.]
 [ 20.   0.   0.]
 [  0.   0. -50.]]

The von Mises stress for a general state of stress is

\begin{equation} \sigma _{v}=\sqrt{\frac {1}{2}\big((\sigma_{x}-\sigma_{y})^{2}+(\sigma_{y}-\sigma_{z})^{2}+(\sigma_{z}-\sigma_{x})^{2}+6(\tau_{xy}^{2}+\tau_{yz}^{2}+\tau_{xz}^{2})\big)} \tag{9} \end{equation}

or by the principal stresses:

\begin{equation} \sigma _{v}=\sqrt{\frac {1}{2}\big((\sigma_{1th}-\sigma_{2nd})^{2}+(\sigma_{2nd}-\sigma_{3rd})^{2}+(\sigma_{3rd}-\sigma_{1th})^{2}\big)} \tag{10} \end{equation}
In [13]:
vonMises= ((1/2)*((L[0]-L[1])**2 + (L[0]-L[2])**2 + (L[1]-L[2])**2))**0.5
print('{0:0.4f}'.format(vonMises))
93.2738

Alternatively:

In [14]:
vonMises=((3/2)*(np.sum(sdev**2)))**(1/2)
print('{0:0.4f}'.format(vonMises))
93.2738
How is von Mises stress useful in a lightweight design process? To be discussed in lectures.

Python tips & tricks

The stress represented as a 3x3 matrix is quite often a sparse matrix. For instance, the matrix representation of a unidirectional stress has only one non-zero component and eight zeros. In such cases, modifying component(s) of an existing zero matrix requires less coding:

In [15]:
sigA = np.zeros((3,3))
sigA[0,0]=100
print(sigA)
[[100.   0.   0.]
 [  0.   0.   0.]
 [  0.   0.   0.]]
In [16]:
sig = np.zeros((3,3))
sig[1,2],sig[2,1]=50,50
print(sig)
[[ 0.  0.  0.]
 [ 0.  0. 50.]
 [ 0. 50.  0.]]

A function with default values (and therefore the arguments are optional) can be a useful alternative:

In [17]:
def stressTensor(s1=0.0,s2=0.0,s3=0.0,s12=0.0,s13=0.0,s23=0.0):
    return np.array ( [ [s1 ,  s12,   s13 ],
                      [  s12,   s2,   s23 ],
                      [  s13,  s23,    s3 ]  ])

sigB=stressTensor(s2=75)
sigC=stressTensor(s13=60,s3=80)

print(sigB)
print()
print(sigC)
[[ 0.  0.  0.]
 [ 0. 75.  0.]
 [ 0.  0.  0.]]

[[ 0.  0. 60.]
 [ 0.  0.  0.]
 [60.  0. 80.]]

Assignment versus numpy.copy()

Remember that assignment statements in Python do not copy objects, and an array is a object in this sense. Hence, if a new variable is assigned to an existing variable pointing to an array as:

In [18]:
sigD=sigC

modifying a component of the new sigD

In [19]:
sigD[0,0]=99

will also modify sigC (or actually, sigC is still pointing to the same object):

In [20]:
print(sigC)
[[99.  0. 60.]
 [ 0.  0.  0.]
 [60.  0. 80.]]

the numpy function numpy.copy() is similar to copy.deepcopy() for built-in mutable data types such as lists and dictionaries:

In [21]:
sigE=np.copy(sigB)
In [22]:
sigE[1,1]=55

print(sigE)
print()
print(sigC)
[[ 0.  0.  0.]
 [ 0. 55.  0.]
 [ 0.  0.  0.]]

[[99.  0. 60.]
 [ 0.  0.  0.]
 [60.  0. 80.]]

Output formatting

Consider the following example with random numbers:

In [23]:
from random import random

sigF = stressTensor(s1=100*random(),s2=100*random(),s3=100*random(),s12=0.01*random())

print(sigF)
[[9.90940116e+01 1.05842859e-03 0.00000000e+00]
 [1.05842859e-03 8.27413814e+01 0.00000000e+00]
 [0.00000000e+00 0.00000000e+00 4.05448285e+01]]

The readability of this array is rather poor, and the precision is probably far beyond what is needed for any practial cases. Now, we may apply numpy.round():

In [24]:
print(np.round(sigF,2))
[[99.09  0.    0.  ]
 [ 0.   82.74  0.  ]
 [ 0.    0.   40.54]]

The numpy.round() function is however not a formatting function but rather a operator returning a new array. A more proper and general approach is to use numpy.array2string() function:

In [25]:
print(np.array2string(sigF, precision=2, suppress_small=True, separator='    ', floatmode='maxprec') )
[[99.09     0.       0.  ]
 [ 0.      82.74     0.  ]
 [ 0.       0.      40.54]]

References and further readings

TODO

TOC Next Prev

Disclaimer:This site is designed for educational purposes only. There are most likely errors, mistakes, typos, and poorly crafted statements that are not detected yet... www.ntnu.edu/employees/nils.p.vedvik

Copyright 2024, All rights reserved