forked from simpeg/simpeg
/
matutils.py
171 lines (118 loc) · 4.08 KB
/
matutils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
from __future__ import division
import numpy as np
from discretize.utils import (
Zero, Identity, mkvc, sdiag, sdInv, speye, kron3, spzeros, ddx, av,
av_extrap, ndgrid, ind2sub, sub2ind, getSubArray, inv3X3BlockDiagonal,
inv2X2BlockDiagonal, TensorType, makePropertyTensor, invPropertyTensor,
)
def avExtrap(**kwargs):
raise Exception("avExtrap has been depreciated. Use av_extrap instead.")
def diagEst(matFun, n, k=None, approach='Probing'):
"""
Estimate the diagonal of a matrix, A. Note that the matrix may be a
function which returns A times a vector.
Three different approaches have been implemented:
1. Probing: cyclic permutations of vectors with 1's and 0's (default)
2. Ones: random +/- 1 entries
3. Random: random vectors
:param callable matFun: takes a (numpy.ndarray) and multiplies it by a matrix to estimate the diagonal
:param int n: size of the vector that should be used to compute matFun(v)
:param int k: number of vectors to be used to estimate the diagonal
:param str approach: approach to be used for getting vectors
:rtype: numpy.ndarray
:return: est_diag(A)
Based on Saad http://www-users.cs.umn.edu/~saad/PDF/umsi-2005-082.pdf,
and http://www.cita.utoronto.ca/~niels/diagonal.pdf
"""
if type(matFun).__name__ == 'ndarray':
A = matFun
def matFun(v):
return A.dot(v)
if k is None:
k = np.floor(n/10.)
if approach.upper() == 'ONES':
def getv(n, i=None):
v = np.random.randn(n)
v[v < 0] = -1.
v[v >= 0] = 1.
return v
elif approach.upper() == 'RANDOM':
def getv(n, i=None):
return np.random.randn(n)
else: # if approach == 'Probing':
def getv(n, i):
v = np.zeros(n)
v[i:n:k] = 1.
return v
Mv = np.zeros(n)
vv = np.zeros(n)
for i in range(0, k):
vk = getv(n, i)
Mv += matFun(vk)*vk
vv += vk*vk
d = Mv/vv
return d
def uniqueRows(M):
b = np.ascontiguousarray(M).view(np.dtype(
(np.void, M.dtype.itemsize * M.shape[1]))
)
_, unqInd = np.unique(b, return_index=True)
_, invInd = np.unique(b, return_inverse=True)
unqM = M[unqInd]
return unqM, unqInd, invInd
def cartesian2spherical(m):
""" Convert from cartesian to spherical """
# nC = int(len(m)/3)
x = m[:, 0]
y = m[:, 1]
z = m[:, 2]
a = (x**2. + y**2. + z**2.)**0.5
t = np.zeros_like(x)
t[a > 0] = np.arcsin(z[a > 0]/a[a > 0])
p = np.zeros_like(x)
p[a > 0] = np.arctan2(y[a > 0], x[a > 0])
m_atp = np.r_[a, t, p]
return m_atp
def spherical2cartesian(m):
""" Convert from spherical to cartesian """
a = m[:, 0] + 1e-8
t = m[:, 1]
p = m[:, 2]
m_xyz = np.r_[a*np.cos(t)*np.cos(p),
a*np.cos(t)*np.sin(p),
a*np.sin(t)]
return m_xyz
def dip_azimuth2cartesian(dip, azm_N):
"""
dip_azimuth2cartesian(dip,azm_N)
Function converting degree angles for dip and azimuth from north to a
3-components in cartesian coordinates.
INPUT
dip : Value or vector of dip from horizontal in DEGREE
azm_N : Value or vector of azimuth from north in DEGREE
OUTPUT
M : [n-by-3] Array of xyz components of a unit vector in cartesian
Created on Dec, 20th 2015
@author: dominiquef
"""
azm_N = np.asarray(azm_N)
dip = np.asarray(dip)
# Number of elements
nC = azm_N.size
M = np.zeros((nC, 3))
# Modify azimuth from North to cartesian-X
azm_X = (450. - np.asarray(azm_N)) % 360.
inc = -np.deg2rad(np.asarray(dip))
dec = np.deg2rad(azm_X)
M[:, 0] = np.cos(inc) * np.cos(dec)
M[:, 1] = np.cos(inc) * np.sin(dec)
M[:, 2] = np.sin(inc)
return M
def coterminal(theta):
"""
Compute coterminal angle so that [-pi < theta < pi]
"""
sub = theta[np.abs(theta) >= np.pi]
sub = -np.sign(sub) * (2*np.pi-np.abs(sub))
theta[np.abs(theta) >= np.pi] = sub
return theta