Efficient extraction of eigenvalues from a list of tensors

When you manipulate FEM results you generally have either a: * scalar field, * vector field, * tensor field.

With tensorial results, it is often useful to extract the eigenvalues in order to find the principal values.

I have found that it is easier to store the components of the tensors in a 6 column pandas dataframe (because of the symmetric property of stress and strain tensors)

import pandas as pd
node = [1001, 1002, 1003, 1004] #when dealing with FEM results you should remember at which element/node the result is computed (in the example, let's assume that we look at node from 1001 to 1004)
tensor1= [1,1,1,0,0,0] #eigen : 1
tensor2= [4,-1,0,2,2,1] #eigen : 5.58443, -1.77931, -0.805118
tensor3= [1,6,5,3,3,1] #eigen : 8.85036, 4.46542, -1.31577
tensor4= [1,2,3,0,0,0] #eigen : 1, 2, 3
df = pd.DataFrame([tensor1, tensor2, tensor3, tensor4], columns=["XX","YY","ZZ","XY","XZ","YZ"])
df.index = node
df
XX YY ZZ XY XZ YZ
1001 1 1 1 0 0 0
1002 4 -1 0 2 2 1
1003 1 6 5 3 3 1
1004 1 2 3 0 0 0

If you want to extract the eigenvalues of a tensor with numpy you have to pass a n by n ndarray to the eigenvalue function. In order to avoid having to loop over each node, this oneliner is highly optimized and will help you invert a large number of tensors efficiently.

The steps are basically, create a list of n by n values (here n=3) in the right order => reshape it to a list of tensors => pass it to the eigenvals function

import numpy as np
from numpy import linalg as LA
eigenvals = LA.eigvals(df[["XX","XY","XZ","XY","YY","YZ","XZ","YZ","ZZ"]].values.reshape(len(df),3,3))
eigenvals
array([[ 1.        ,  1.        ,  1.        ],
       [ 5.58442834, -0.80511809, -1.77931025],
       [-1.31577211,  8.85035616,  4.46541595],
       [ 1.        ,  2.        ,  3.        ]])