2

Hey so I'm working on this code for a material analysis. I have a matrix generated for each layer of the material and I want to save each of these matrices as their own element. The way I was doing this was by saving it to a dictionary. I then form one matrix by summing all the values of the dictionary. Now I do this for three different conditions which leaves me with 3 matrices: A, B, and D. I want to make a matrix of all of these so that it looks like:

    | A B |
    | B D |

However I can't get it to print properly as it always says matrix: then one of the matrices such as A. It prints the second matrix, B, on the third line where A ended instead of being next to A. I also need to perform future operations on this massive matrix so I'm wondering what the best way to go about that would be. This is a part of my code:

    Qbars = {}
    for i in plies:

    Qbar11 = Q11 * math.cos(float(thetas[j]))**4 + Q22        *math.sin(float(thetas[j]))**4 + \
        2 * (Q12 + 2 * Q66) * math.sin(float(thetas[j]))**2 * math.cos(float(thetas[j]))**2
        Qbar22 = Q11 * math.sin(float(thetas[j]))**4 + Q22 *math.cos(float(thetas[j]))**4 + \
        2 * (Q12 + 2 * Q66) * math.sin(float(thetas[j]))**2 * math.cos(float(thetas[j]))**2
        Qbar12 = (Q11 + Q22 - 4 * Q66) * math.sin(float(thetas[j]))**2 * \
        math.cos(float(thetas[j]))**2 + Q12 * (math.cos(float(thetas[j]))**4 + \
        math.sin(float(thetas[j]))**4)
        Qbar66 = (Q11 + Q22 - 2 * Q12 - 2 * Q66) * math.sin(float(thetas[j]))**2 * \
        math.cos(float(thetas[j])) **2 + Q66 * (math.sin(float(thetas[j]))**4 + \
        math.cos(float(thetas[j]))**4)
        Qbar16 = (Q11 - Q12 - 2 * Q66) * math.cos(float(thetas[j]))**3 * \
        math.sin(float(thetas[j])) - (Q22 - Q12 - 2 * Q66) * math.cos(float(thetas[j])) * \
        math.sin(float(thetas[j]))**3
        Qbar26 = (Q11 - Q12 - 2 * Q66) * math.cos(float(thetas[j])) * \
        math.sin(float(thetas[j]))**3 - (Q22 - Q12 - 2 * Q66) * \
        math.cos(float(thetas[j]))**3 * math.sin(float(thetas[j]))

        Qbar = np.matrix ([[Qbar11, Qbar12, Qbar16], [Qbar12, Qbar22, Qbar26], \
        [Qbar16, Qbar26, Qbar66]])

        Qbars[i] = Qbar

        if len(thetas) == 1:
            j = 0
        else:
            j = j + 1

    k=0
    Alist = {}
    for i in plies:
        Alist[i] = Qbars[i].dot(h[k])
        if len(h) == 1:
            k = 0
        else:
            k = k + 1
    A = sum(Alist.values())

    ABD = ([A, B],[B, D])
    print ABD

One of the next operations I intend to perform would be to multiply the matrix by a 6x1 array that would look like such:

    | Nx |     | A A A  B B B |
    | Ny |     | A A A  B B B |
    | Nxy|     | A A A  B B B | 
    ------  *  ----------------
    | Mx |     | B B B  D D D |
    | My |     | B B B  D D D |
    | Mxy|     | B B B  D D D |

What would be the best way to go about doing this?

EDIT: I made this shorter code to reproduce what I'm dealing with, I couldn't think of how to make it even smaller.

import os
import numpy as np
import math
os.system('cls')
ang = raw_input("ENTER 0 (SPACE) 45 ")
thetas = [int(i) for i in ang.split()]
x = 40
h = [3, 5]
y = [1,2]
j = 0
Qbars = {}
for i in y:
    theta = [thetas[j] * math.pi / 180]
    Q = math.sin(float(thetas[j]))
    Qbar = np.matrix ([[Q, Q, Q], [Q, Q, Q], [Q, Q, Q]])

    Qbars[i] = Qbar

    if len(thetas) == 1:
        j = 0
    else:
        j = j + 1

print Qbars
k=0
Alist = {}
for i in y:
    Alist[i] = Qbars[i].dot(h[k])
    if len(h) == 1:
        k = 0
    else:
        k = k + 1
A = sum(Alist.values())

AAAA = ([A, A], [A, A])
print AAAA
test = raw_input("Press ENTER to close")
Aaron
  • 10,133
  • 1
  • 24
  • 40
Azyru
  • 43
  • 1
  • 6
  • you need to clarify what you're asking. the code you've provided runs without any errors and prints roughly what I'd expect it to. – Aaron Oct 20 '17 at 23:32
  • 1
    I'd also suggest not using `np.matrix`. the `np.array` is much more flexible. – Aaron Oct 20 '17 at 23:36

1 Answers1

6

As others have noted, the matrix class is pretty much deprecated by now. They are more limited than ndarrays, with very little additional functionality. The main reason why people prefer to use numpy matrices is that linear algebra (in particular, matrix multiplication) works more naturally for matrices.

However, as far as I can tell you're using np.dot rather than the overloaded arithmetic operators of the matrix class to begin with, so you would not see any loss of functionality from using np.array instead. Furthermore, if you would switch to python 3.5 or newer, you could use the @ matrix multiplication operator that would let you write things such as

Alist[i] = Qbars[i] @ h[k]

In the following I'll use the ndarray class instead of the matrix class for the above reasons.

So, your question has two main parts: creating your block matrix and multiplying the result with a vector. I suggest using an up-to-date numpy version, since there's numpy.block introduced in version 1.13. This conveniently does exactly what you want it to do:

>>> import numpy as np
>>> A,B,C = (np.full((3,3),k) for k in range(3))
>>> A
array([[0, 0, 0],
       [0, 0, 0],
       [0, 0, 0]])
>>> B
array([[1, 1, 1],
       [1, 1, 1],
       [1, 1, 1]])
>>> C
array([[2, 2, 2],
       [2, 2, 2],
       [2, 2, 2]])
>>> np.block([[A,B],[B,C]])
array([[0, 0, 0, 1, 1, 1],
       [0, 0, 0, 1, 1, 1],
       [0, 0, 0, 1, 1, 1],
       [1, 1, 1, 2, 2, 2],
       [1, 1, 1, 2, 2, 2],
       [1, 1, 1, 2, 2, 2]])

Similarly, you can concatenate your two 3-length vectors using np.concatenate or one of the stacking methods (these are available in older versions too).

Now, the problem is that you can't multiply a matrix of shape (6,1) with a matrix of shape (6,6), so the question is what you're really trying to do here. In case you want to multiply each element of your matrix with the corresponding row of your vector, you can just multiply your arrays (of class np.ndarray!) and make use of array broadcasting:

>>> Q = np.block([[A,B],[B,C]])    # (6,6)-shape array
>>> v = np.arange(6).reshape(-1,1) # (6,1)-shape array
>>> v * Q
array([[ 0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  1,  1,  1],
       [ 0,  0,  0,  2,  2,  2],
       [ 3,  3,  3,  6,  6,  6],
       [ 4,  4,  4,  8,  8,  8],
       [ 5,  5,  5, 10, 10, 10]])

The other option is that you want to do matrix-vector multiplication, but then either you have to transpose your vector (in order to multiply it with the matrix from the right) or swap the order of the matrix and the vector (multiplying the vector with the matrix from the left). Example for the former:

>>> v.T @ Q  # python 3.5 and up
array([[12, 12, 12, 27, 27, 27]])

>>> v.T.dot(Q)
array([[12, 12, 12, 27, 27, 27]])

Another benefit of arrays (rather than matrices) is that arrays can be multidimensional. Instead of putting numpy arrays inside a dict and summing them that way, you could define a 3d array (a collection of 2d arrays along a third axis), then you could sum along the third dimension. One huge benefit of numpy is its efficient memory need and performance, and these aspects are strongest if you use numpy objects and methods all through your code. Mixing native python objects (such as dicts, zips, loops) typically hinders performance.