0

I have a matrix of triangles where each line has 3 verticies: elementSet:

Element Number      Vertices 
    2           473    1159   917
    3           271    1026   816

And I also have a matrix of nodes that assign a 2d coordinated for every vertice nodeSet:

Vertice Number                 (X,Y)
917             5.487167292060809 2.195789288329368 
271             5.448888739433895 2.38822856765269 

I've written some methods to handle the area calculation, they are contained in a class:

  def findArea(self):
        self.elementsArea = nu.zeros((self.elementSet.shape[0],1))
        self.elementsArea[:] = self.calcArea(*self.elementSet[:,-3:])

  #Calculate the area of 3 points
  def calcArea (self,p1,p2,p3):
      [p1,p2,p3] = [self.nodeCoord(p1),self.nodeCoord(p2),self.nodeCoord(p3)]

      return 0.5*abs(p1[Xc]*(p2[Yc] - p3[Yc]) + p2[Xc]*(p3[Yc]-p1[Yc]) + p3[Xc]*(p1[Yc] - p2[Yc]))


  # returns the vertices of a point
  def nodeCoord(self, point):
        return(self.nodeSet[point-1,-3:-1]) 

where the function calcArea works fine but I want to apply a function to every element of a matrix and assign to another matrix without using a loop.

I have to write something like:

A[:] = func(B[:])

In def findArea() I tried to do something like this but it gives me the following error:

calcArea() takes 4 positional arguments but 2171 were given

I wanna use calcArea() to calculate the area passing arrays as arguments the same way I did in this exemple:

import numpy as np


def test(x,y):
    return x*y

f = np.array([[1,2,5,6,7] , [3,4,9,6,7] ,[6,7,23,34,32]])

print(test(f[0,:],f[1,:]))

I am trying to apply calcArea method but I am getting now only a 2 dimmensions array when I was suppose to get an array the same dimmension the original vectors

a.calcArea(f[0,:],f[1,:],f[2,:])
 array([ 7.5,  0. ])
6
  • 1
    Do you have to do this manually, can't you use other packages such as pandas Commented Oct 31, 2015 at 12:51
  • I have to do it manually =(. if you use numpy.sin() you can apply to a matrix and I have to do the same Commented Oct 31, 2015 at 13:19
  • 1
    How about map(function, sequence)? Commented Oct 31, 2015 at 13:42
  • 1
    Do you understand the error? Do us a favor add a small script, function and data that reproduces the error - something we can run with a quick cut-n-paste. Commented Oct 31, 2015 at 14:59
  • I am really trying to emulate the error somehow so I show you guys. Commented Oct 31, 2015 at 15:17

2 Answers 2

2

If you can rearrange your data into a set of three 2D arrays containing the x,y coordinates for the first, second and third vertices of all your triangles (e.g. with dimensions (2, n) where n is the number of triangles) then you can easily vectorize the computation over all triangles:

import numpy as np

# adapted from your code. here p1, p2 and p3 are (2, ...) vectors of x,y coords.
def triangle_area(p1, p2, p3):
      return 0.5 * np.abs(p1[0] * (p2[1] - p3[1]) +
                          p2[0] * (p3[1] - p1[1]) +
                          p3[0] * (p1[1] - p2[1]))

n = 100000

# some random vertex data
vert_data = np.random.randn(3, 2, n)

# each of these is a (2, n) vector of x,y coordinates
P1, P2, P3 = vert_data

# a 100000-long vector of areas
areas = triangle_area(P1, P2, P3)

Timing:

In [41]: %%timeit P1, P2, P3 = np.random.randn(3, 2, 100000)
   ....: triangle_area(P1, P2, P3)
   ....: 
1000 loops, best of 3: 1.09 ms per loop
Sign up to request clarification or add additional context in comments.

Comments

1

Using your test and f:

In [420]: test(f[0,:],f[1,:])
Out[420]: array([ 3,  8, 45, 36, 49])
In [421]: test(*f[:2,:])
Out[421]: array([ 3,  8, 45, 36, 49])

When indexing on the 1st dimension, (*...) does the same thing. But in your class case you are trying to select columns, not rows

In [422]: f1=f.T
In [423]: test(f1[:,1],f1[:,2])
Out[423]: array([ 18,  28, 207, 204, 224])
In [424]: test(*f1[:,:2])
...
TypeError: test() takes 2 positional arguments but 5 were given

(*f1...) expands to (f1[0,:2],f1[1,:2],f1[2,:2],etc). * expansion is in effect an interation on the 1st dimensions.


calcArea takes 3 arguments, but self.calcArea(*self.elementSet[:,-3:]) expands along the 1st dimension of elementSet, not the last size 3 dimension. Try

self.calcArea(self.elementSet[:,0], self.elementSet[:,1], self.elementSet[:,2])

1 Comment

I understand that. What it does not make sense is why it works with test but not with calcArea()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.