Home > Software design >  What is the most efficient way to handle conversion from full to symmetric second order tensors usin
What is the most efficient way to handle conversion from full to symmetric second order tensors usin

Time:12-19

I am processing symmetric second order tensors (of stress) using numpy. In order to transform the tensors I have to generate a fully populated tensor, do the transformation and then recover the symmetric tensor in the rotated frame.

My input is a 2D numpy array of symmetric tensors (nx6). The code below works, but I'm pretty sure there must be a more efficient and/or elegant way to manipulate the arrays but I can't seem to figure it out.

I anyone can anyone suggest an improvement I'd be very grateful? The sample input is just 2 symmetric tensors but in use this could be millions of tensors, hence the concernr with efficiency

Thanks,

Doug

# Sample symmetric input (S11, S22, S33, S12, S23, S13)
sym_tens_in=np.array([[0,9], [1,10], [2,11], [3,12], [4,13], [5,14]])
   
# Expand to full tensor
tens_full=np.array([[sym_tens_in[0], sym_tens_in[3], sym_tens_in[4]],
                    [sym_tens_in[3], sym_tens_in[1], sym_tens_in[5]],
                    [sym_tens_in[4], sym_tens_in[5], sym_tens_in[2]]])

# Transpose and reshape to n x 3 x 3 
tens_full=np.transpose(tens_full, axes=(2, 0, 1))

# This where the work on the full tensor will go....

# Reshape for extraction of the symmetric tensor
tens_full=np.reshape(tens_full, (2,9))

# Create an array for the test ouput symmetric tensor
sym_tens_out=np.empty((2,6), dtype=np.int32)

# Extract the symmetric components
sym_tens_out[:,0]=tens_full[:,0]
sym_tens_out[:,1]=tens_full[:,4]
sym_tens_out[:,2]=tens_full[:,8]
sym_tens_out[:,3]=tens_full[:,2]
sym_tens_out[:,4]=tens_full[:,3]
sym_tens_out[:,5]=tens_full[:,5]

# Transpose....
sym_tens_out=np.transpose(sym_tens_out)

CodePudding user response:

I guess that numpy.einsum should be faster and more memory-efficient than creating a new array for the full tensor, reshaping it, and then extracting the symmetric components

import numpy as np

sym_tens_in = np.array([[0, 9], [1, 10], [2, 11], [3, 12], [4, 13], [5, 14]])

# Compute the indices for the full tensor using einsum
full_idx = np.einsum('ij->ijkl', np.ones((2, 6)))

# Extract the full tensor using the computed indices
tens_full = sym_tens_in[full_idx]

# This where the work on the full tensor will go....

# Compute the indices for the symmetric tensor using einsum
sym_idx = np.einsum('ijkl->ij', full_idx * np.array([1, 0, 0, 1, 1, 0]))

# Extract the symmetric tensor using the computed indices
sym_tens_out = sym_tens_in[sym_idx]

CodePudding user response:

This won't be any faster, but it's more compact:

In [166]: idx=np.array([0,3,4,3,1,5,4,5,2]).reshape(3,3)
In [167]: sym_tens_in[idx].transpose(2,0,1)
Out[167]: 
array([[[ 0,  3,  4],
        [ 3,  1,  5],
        [ 4,  5,  2]],

       [[ 9, 12, 13],
        [12, 10, 14],
        [13, 14, 11]]])

The transpose could be done first:

sym_tens_in.T[:,idx]

Similarly the reverse mapping can be done with:

In [168]: idx1 = [0,4,8,1,2,5]
In [171]: tens_full.reshape(2,-1)[:,idx1]
Out[171]: 
array([[ 0,  1,  2,  3,  4,  5],
       [ 9, 10, 11, 12, 13, 14]])

with the optional transpose.

  • Related