mirror of
https://github.com/wassname/simpeg.git
synced 2026-07-14 11:18:18 +08:00
renaming to ensure capitals
This commit is contained in:
@@ -0,0 +1,265 @@
|
||||
import numpy as np
|
||||
from scipy import sparse as sp
|
||||
from matutils import mkvc, ndgrid, sub2ind
|
||||
from sputils import sdiag
|
||||
|
||||
|
||||
def volTetra(xyz, A, B, C, D):
|
||||
"""
|
||||
Returns the volume for tetrahedras volume specified by the indexes A to D.
|
||||
|
||||
:param numpy.array xyz: X,Y,Z vertex vector
|
||||
:param numpy.array A,B,C,D: vert index of the tetrahedra
|
||||
:rtype: numpy.array
|
||||
:return: V, volume of the tetrahedra
|
||||
|
||||
Algorithm http://en.wikipedia.org/wiki/Tetrahedron#Volume
|
||||
|
||||
.. math::
|
||||
|
||||
V = {1 \over 3} A h
|
||||
|
||||
V = {1 \over 6} | ( a - d ) \cdot ( ( b - d ) ( c - d ) ) |
|
||||
|
||||
"""
|
||||
|
||||
AD = xyz[A, :] - xyz[D, :]
|
||||
BD = xyz[B, :] - xyz[D, :]
|
||||
CD = xyz[C, :] - xyz[D, :]
|
||||
|
||||
V = (BD[:, 0]*CD[:, 1] - BD[:, 1]*CD[:, 0])*AD[:, 2] - (BD[:, 0]*CD[:, 2] - BD[:, 2]*CD[:, 0])*AD[:, 1] + (BD[:, 1]*CD[:, 2] - BD[:, 2]*CD[:, 1])*AD[:, 0]
|
||||
return V/6
|
||||
|
||||
|
||||
def indexCube(nodes, gridSize, n=None):
|
||||
"""
|
||||
Returns the index of nodes on the mesh.
|
||||
|
||||
|
||||
Input:
|
||||
nodes - string of which nodes to return. e.g. 'ABCD'
|
||||
gridSize - size of the nodal grid
|
||||
n - number of nodes each i,j,k direction: [ni,nj,nk]
|
||||
|
||||
|
||||
Output:
|
||||
index - index in the order asked e.g. 'ABCD' --> (A,B,C,D)
|
||||
|
||||
TWO DIMENSIONS::
|
||||
|
||||
node(i,j) node(i,j+1)
|
||||
A -------------- B
|
||||
| |
|
||||
| cell(i,j) |
|
||||
| I |
|
||||
| |
|
||||
D -------------- C
|
||||
node(i+1,j) node(i+1,j+1)
|
||||
|
||||
|
||||
THREE DIMENSIONS::
|
||||
|
||||
node(i,j,k+1) node(i,j+1,k+1)
|
||||
E --------------- F
|
||||
/| / |
|
||||
/ | / |
|
||||
/ | / |
|
||||
node(i,j,k) node(i,j+1,k)
|
||||
A -------------- B |
|
||||
| H ----------|---- G
|
||||
| /cell(i,j) | /
|
||||
| / I | /
|
||||
| / | /
|
||||
D -------------- C
|
||||
node(i+1,j,k) node(i+1,j+1,k)
|
||||
|
||||
"""
|
||||
|
||||
assert type(nodes) == str, "Nodes must be a str variable: e.g. 'ABCD'"
|
||||
assert type(gridSize) == np.ndarray, "Number of nodes must be an ndarray"
|
||||
nodes = nodes.upper()
|
||||
# Make sure that we choose from the possible nodes.
|
||||
possibleNodes = 'ABCD' if gridSize.size == 2 else 'ABCDEFGH'
|
||||
for node in nodes:
|
||||
assert node in possibleNodes, "Nodes must be chosen from: '%s'" % possibleNodes
|
||||
dim = gridSize.size
|
||||
if n is None:
|
||||
n = gridSize - 1
|
||||
|
||||
if dim == 2:
|
||||
ij = ndgrid(np.arange(n[0]), np.arange(n[1]))
|
||||
i, j = ij[:, 0], ij[:, 1]
|
||||
elif dim == 3:
|
||||
ijk = ndgrid(np.arange(n[0]), np.arange(n[1]), np.arange(n[2]))
|
||||
i, j, k = ijk[:, 0], ijk[:, 1], ijk[:, 2]
|
||||
else:
|
||||
raise Exception('Only 2 and 3 dimensions supported.')
|
||||
|
||||
nodeMap = {'A': [0, 0, 0], 'B': [0, 1, 0], 'C': [1, 1, 0], 'D': [1, 0, 0],
|
||||
'E': [0, 0, 1], 'F': [0, 1, 1], 'G': [1, 1, 1], 'H': [1, 0, 1]}
|
||||
out = ()
|
||||
for node in nodes:
|
||||
shift = nodeMap[node]
|
||||
if dim == 2:
|
||||
out += (sub2ind(gridSize, np.c_[i+shift[0], j+shift[1]]).flatten(), )
|
||||
elif dim == 3:
|
||||
out += (sub2ind(gridSize, np.c_[i+shift[0], j+shift[1], k+shift[2]]).flatten(), )
|
||||
|
||||
return out
|
||||
|
||||
|
||||
def faceInfo(xyz, A, B, C, D, average=True, normalizeNormals=True):
|
||||
"""
|
||||
function [N] = faceInfo(y,A,B,C,D)
|
||||
|
||||
Returns the averaged normal, area, and edge lengths for a given set of faces.
|
||||
|
||||
If average option is FALSE then N is a cell array {nA,nB,nC,nD}
|
||||
|
||||
|
||||
Input:
|
||||
xyz - X,Y,Z vertex vector
|
||||
A,B,C,D - vert index of the face (counter clockwize)
|
||||
|
||||
Options:
|
||||
average - [true]/false, toggles returning all normals or the average
|
||||
|
||||
Output:
|
||||
N - average face normal or {nA,nB,nC,nD} if average = false
|
||||
area - average face area
|
||||
edgeLengths - exact edge Lengths, 4 column vector [AB, BC, CD, DA]
|
||||
|
||||
see also testFaceNormal testFaceArea
|
||||
|
||||
@author Rowan Cockett
|
||||
|
||||
Last modified on: 2013/07/26
|
||||
|
||||
"""
|
||||
assert type(average) is bool, 'average must be a boolean'
|
||||
assert type(normalizeNormals) is bool, 'normalizeNormals must be a boolean'
|
||||
# compute normal that is pointing away from you.
|
||||
#
|
||||
# A -------A-B------- B
|
||||
# | |
|
||||
# | |
|
||||
# D-A (X) B-C
|
||||
# | |
|
||||
# | |
|
||||
# D -------C-D------- C
|
||||
|
||||
AB = xyz[B, :] - xyz[A, :]
|
||||
BC = xyz[C, :] - xyz[B, :]
|
||||
CD = xyz[D, :] - xyz[C, :]
|
||||
DA = xyz[A, :] - xyz[D, :]
|
||||
|
||||
def cross(X, Y):
|
||||
return np.c_[X[:, 1]*Y[:, 2] - X[:, 2]*Y[:, 1],
|
||||
X[:, 2]*Y[:, 0] - X[:, 0]*Y[:, 2],
|
||||
X[:, 0]*Y[:, 1] - X[:, 1]*Y[:, 0]]
|
||||
|
||||
nA = cross(AB, DA)
|
||||
nB = cross(BC, AB)
|
||||
nC = cross(CD, BC)
|
||||
nD = cross(DA, CD)
|
||||
|
||||
length = lambda x: np.sqrt(x[:, 0]**2 + x[:, 1]**2 + x[:, 2]**2)
|
||||
normalize = lambda x: x/np.kron(np.ones((1, x.shape[1])), mkvc(length(x), 2))
|
||||
if average:
|
||||
# average the normals at each vertex.
|
||||
N = (nA + nB + nC + nD)/4 # this is intrinsically weighted by area
|
||||
# normalize
|
||||
N = normalize(N)
|
||||
else:
|
||||
if normalizeNormals:
|
||||
N = [normalize(nA), normalize(nB), normalize(nC), normalize(nD)]
|
||||
else:
|
||||
N = [nA, nB, nC, nD]
|
||||
|
||||
# Area calculation
|
||||
#
|
||||
# Approximate by 4 different triangles, and divide by 2.
|
||||
# Each triangle is one half of the length of the cross product
|
||||
#
|
||||
# So also could be viewed as the average parallelogram.
|
||||
#
|
||||
# TODO: This does not compute correctly for concave quadrilaterals
|
||||
area = (length(nA)+length(nB)+length(nC)+length(nD))/4
|
||||
|
||||
return N, area
|
||||
|
||||
|
||||
def inv3X3BlockDiagonal(a11, a12, a13, a21, a22, a23, a31, a32, a33):
|
||||
""" B = inv3X3BlockDiagonal(a11, a12, a13, a21, a22, a23, a31, a32, a33)
|
||||
|
||||
inverts a stack of 3x3 matrices
|
||||
|
||||
Input:
|
||||
A - a11, a12, a13, a21, a22, a23, a31, a32, a33
|
||||
|
||||
Output:
|
||||
B - inverse
|
||||
"""
|
||||
|
||||
a11 = mkvc(a11)
|
||||
a12 = mkvc(a12)
|
||||
a13 = mkvc(a13)
|
||||
a21 = mkvc(a21)
|
||||
a22 = mkvc(a22)
|
||||
a23 = mkvc(a23)
|
||||
a31 = mkvc(a31)
|
||||
a32 = mkvc(a32)
|
||||
a33 = mkvc(a33)
|
||||
|
||||
detA = a31*a12*a23 - a31*a13*a22 - a21*a12*a33 + a21*a13*a32 + a11*a22*a33 - a11*a23*a32
|
||||
|
||||
b11 = +(a22*a33 - a23*a32)/detA
|
||||
b12 = -(a12*a33 - a13*a32)/detA
|
||||
b13 = +(a12*a23 - a13*a22)/detA
|
||||
|
||||
b21 = +(a31*a23 - a21*a33)/detA
|
||||
b22 = -(a31*a13 - a11*a33)/detA
|
||||
b23 = +(a21*a13 - a11*a23)/detA
|
||||
|
||||
b31 = -(a31*a22 - a21*a32)/detA
|
||||
b32 = +(a31*a12 - a11*a32)/detA
|
||||
b33 = -(a21*a12 - a11*a22)/detA
|
||||
|
||||
B = sp.vstack((sp.hstack((sdiag(b11), sdiag(b12), sdiag(b13))),
|
||||
sp.hstack((sdiag(b21), sdiag(b22), sdiag(b23))),
|
||||
sp.hstack((sdiag(b31), sdiag(b32), sdiag(b33)))))
|
||||
|
||||
return B
|
||||
|
||||
|
||||
def inv2X2BlockDiagonal(a11, a12, a21, a22):
|
||||
""" B = inv2X2BlockDiagonal(a11, a12, a21, a22)
|
||||
|
||||
Inverts a stack of 2x2 matrices by using the inversion formula
|
||||
|
||||
inv(A) = (1/det(A)) * cof(A)^T
|
||||
|
||||
Input:
|
||||
A - a11, a12, a13, a21, a22, a23, a31, a32, a33
|
||||
|
||||
Output:
|
||||
B - inverse
|
||||
"""
|
||||
|
||||
a11 = mkvc(a11)
|
||||
a12 = mkvc(a12)
|
||||
a21 = mkvc(a21)
|
||||
a22 = mkvc(a22)
|
||||
|
||||
# compute inverse of the determinant.
|
||||
detAinv = 1./(a11*a22 - a21*a12)
|
||||
|
||||
b11 = +detAinv*a22
|
||||
b12 = -detAinv*a12
|
||||
b21 = -detAinv*a21
|
||||
b22 = +detAinv*a11
|
||||
|
||||
B = sp.vstack((sp.hstack((sdiag(b11), sdiag(b12))),
|
||||
sp.hstack((sdiag(b21), sdiag(b22)))))
|
||||
|
||||
return B
|
||||
Reference in New Issue
Block a user