import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
import pyshtools as sh
from sympy.physics.quantum.cg import CG,cg_simp
from mpl_toolkits.mplot3d import Axes3D
from scipy.spatial import Delaunay
from scipy.special import sph_harm
import math
import collections
%matplotlib notebook
-
- import hoge as hg は、呼び出しを簡単にしてhg.hageのようにして使うため
- from hoge import hage はhogeの中からhageを特に読み込んで、hageをそのままの名前で使うため
- ベクトル・アレイを使って三角形の計算する
def triweightedcenter(ts):
ret = np.zeros((3,ts.tri.T[0,].size))
for i in range(ts.tri.T[0,].size):
id1 = ts.tri[i,0]
id2 = ts.tri[i,1]
id3 = ts.tri[i,2]
v1 = np.array([ts.X[0,id1],ts.X[1,id1],ts.X[2,id1]])
v2 = np.array([ts.X[0,id2],ts.X[1,id2],ts.X[2,id2]])
v3 = np.array([ts.X[0,id3],ts.X[1,id3],ts.X[2,id3]])
ret[0,i], ret[1,i], ret[2,i] = (v1 + v2 + v3)/3
return ret
-
- 頂点座標を持つ2次元アレイと頂点IDの三つ組を渡して、複数の三角形の重心を計算する(頂点IDトリオ、頂点座標2次元アレイのハンドリング関数は後述)
def triweightedcenter2(tri,X):
ret = np.zeros((3,tri.T[0,].size))
for i in range(tri.T[0,].size):
id1 = tri[i,0]
id2 = tri[i,1]
id3 = tri[i,2]
v1 = np.array([X[0,id1],X[1,id1],X[2,id1]])
v2 = np.array([X[0,id2],X[1,id2],X[2,id2]])
v3 = np.array([X[0,id3],X[1,id3],X[2,id3]])
ret[0,i], ret[1,i], ret[2,i] = (v1 + v2 + v3)/3
return ret
def triarea(v1,v2,v3):
e12 = v2-v1
e13 = v3-v1
ip = np.dot(e12,e13)
r1 = np.sqrt(np.sum(np.power(e12,2)))
r2 = np.sqrt(np.sum(np.power(e13,2)))
costheta = ip/(r1*r2)
sintheta = np.sqrt(1-np.power(costheta,2))
area = 0.5 * r1*r2*sintheta
return area
-
- 頂点座標を持つ2次元アレイと頂点IDの三つ組を渡して、複数の三角形の面積を計算する
def triarea_mult(tri,X):
ret = np.zeros(tri.T[0,].size)
for i in range(tri.T[0,].size):
id1 = tri[i,0]
id2 = tri[i,1]
id3 = tri[i,2]
if (id1-id2)*(id2-id3)*(id3-id1) == 0:
ret[i] = 0
else:
v1 = np.array([X[0,id1],X[1,id1],X[2,id1]])
v2 = np.array([X[0,id2],X[1,id2],X[2,id2]])
v3 = np.array([X[0,id3],X[1,id3],X[2,id3]])
ret[i] = triarea(v1,v2,v3)
return ret
def spheretriplot(ts):
fig = plt.figure()
ax = Axes3D(fig)
ax.plot_trisurf(ts.X[0,],ts.X[1,],ts.X[2,], triangles=ts.tri, cmap=plt.cm.Spectral)
plt.show()
def spheregrid(nlat=10,nlon=10):
phi = 2*math.pi/nlon * np.array([range(nlon)])
theta = math.pi/(nlat-1) * np.array([range(nlat)])
n = 2 + nlon * (nlat-2)
ret = np.zeros((2,n))
ret[0,n-1] = math.pi
for i in range(nlat -2):
for j in range(nlon):
tmp = i * nlon + j + 1
ret[0,tmp] = theta[0,i+1]
ret[1,tmp] = phi[0,j]
n_tri = nlon * 2 + nlon*2*(nlat-3)
tri = np.zeros((n_tri,3),dtype=np.int)
cnt = 0
for i in range(nlon-1):
tri[cnt,0] = 0
tri[cnt,1] = i+1
tri[cnt,2] = i+2
cnt +=1
tri[cnt,0] = 0
tri[cnt,1] = nlon
tri[cnt,2] = 1
cnt +=1
for i in range(nlat-3):
for j in range(nlon-1):
tri[cnt,0] = i*nlon + j + 1
tri[cnt,1] = i*nlon + j + 2
tri[cnt,2] = (i+1)*nlon + j + 2
cnt += 1
tri[cnt,0] = i*nlon + j + 1
tri[cnt,1] = (i+1)*nlon + j + 1
tri[cnt,2] = (i+1)*nlon + j + 2
cnt += 1
tri[cnt,0] = i*nlon + nlon
tri[cnt,1] = i*nlon + 1
tri[cnt,2] = (i+1)*nlon + 1
cnt += 1
tri[cnt,0] = i*nlon + nlon
tri[cnt,1] = (i+1)*nlon + nlon
tri[cnt,2] = (i+1)*nlon + 1
cnt += 1
for i in range(nlon-1):
tri[cnt,0] = (nlat-3)*nlon + i + 1
tri[cnt,1] = (nlat-3)*nlon + i + 2
tri[cnt,2] = n-1
cnt +=1
tri[cnt,0] = (nlat-3)*nlon + nlon-1 + 1
tri[cnt,1] = (nlat-3)*nlon + 1
tri[cnt,2] = n-1
X = np.ndarray((3,n))
for i in range(ret[0,].size):
X[0,i], X[1,i], X[2,i] = np.sin(ret[0,i])*np.cos(ret[1,i]), np.sin(ret[0,i])*np.sin(ret[1,i]), np.cos(ret[0,i])
areas = triarea_mult(tri,X)
weightedcenter = triweightedcenter2(tri,X)
WCpolar = decart2polar3d_ndarray(weightedcenter)
result = collections.namedtuple('result', 'X, vangles, fangles,tri,area,wcenter,')
return result(X=X, vangles=ret, fangles=WCpolar, tri=tri, area = areas, wcenter=weightedcenter)
def decart2polar3d(x,y,z):
r = math.sqrt(x**2+y**2+z**2)
rxy = x**2+y**2
if rxy==0:
phi = 0
theta = 0
if z < 0:
theta = math.pi
else:
if x==0:
phi = math.pi/2
if y < 0:
phi = -math.pi/2
else:
phi = np.arctan(y/x)
theta = np.arccos(z/r)
return [phi,theta,r]
decart2polar3d(0,0,-1)
def decart2polar3d_ndarray(X):
ret = np.zeros_like(X)
for i in range(X[0,].size):
tmp= decart2polar3d(X[0,i],X[1,i],X[2,i])
ret[0,i],ret[1,i],ret[2,i] = tmp
return ret
- 球面場を実数球面調和関数の和として考えることにする
- 球面調和関数係数をpyshtoolsのSHCoeffsクラスのcoeffsメンバーに登録する形で定める
- ランダムに与えることにする
- degree l までの係数は (l+1)^2個となるが、それを(l+1)^2 * 2個の要素を格納できる3次元アレイに格納するのがSHCoeffsクラスのやりかた
def randSHcoef(lmax):
num_coef = (lmax+1)**2
value_re = np.random.randn(num_coef) + 0j
x = sh.SHCoeffs.from_zeros(lmax,'complex')
for l in range(0, lmax+1):
for m in range(-l, l+1):
x.set_coeffs(value_re[l*(l+1)+m], l, m)
return x
def coeff2valreal(cf,phi,theta):
ret = 0
for l in range(0, cf[0,0,].size):
for m in range(-l, l+1):
if m >= 0:
tmp = cf[0,l,m]
ret += sph_harm(m,l,phi,theta).real
else:
tmp = cf[1,l,np.abs(m)]
ret += sph_harm(m,l,phi,theta).imag
return ret
def coeff2valcomplex(cf,phi,theta):
ret = 0+1j
for l in range(0, cf[0,0,].size):
for m in range(-l, l+1):
if m >= 0:
tmp = cf[0,l,m]
else:
tmp = cf[1,l,np.abs(m)]
ret += sph_harm(m,l,phi,theta)
return ret
def SHval(Xpolar,coef):
valreal = np.zeros(Xpolar[0,].size)
valcomplex = np.zeros(Xpolar[0,].size,'complex')
for i in range(Xpolar[0,].size):
valreal[i] = coeff2valreal(coef,Xpolar[0,i],Xpolar[1,i])
valcomplex[i] = coeff2valcomplex(coef,Xpolar[0,i],Xpolar[1,i])
result = collections.namedtuple('result', 'real, clx')
return result(real = valreal,clx=valcomplex)
- 球面調和関数分解、その離散版
- 個々の球面調和関数の分解係数は、球面全体にわたって、場の関数と球面超関数との積分を取ることである
- 離散版は、小領域ごとに場関数の値と球面調和関数の値との積を取り、それを領域全体にわたって、小領域面積で重み付けした積算を取ること
- その処理を個々の球面調和関数についておこない、それを指定の球面調和関数セットについて行う
def SHdecomp(fvalue,area,fangle,l,m):
ret_re = 0
ret_clx = 0 + 0j
for i in range(area.size):
if m < 0:
ret_re += fvalue[i] * sph_harm(m,l,fangle[0,i],fangle[1,i]).imag * area[i]
else:
ret_re += fvalue[i] * sph_harm(m,l,fangle[0,i],fangle[1,i]).real * area[i]
ret_clx += fvalue[i] * sph_harm(m,l,fangle[0,i],fangle[1,i]) * area[i]
return [ret_re,ret_clx]
def SHdecomp_lmax(fvalue,area,fangle,lmax):
xre = sh.SHCoeffs.from_zeros(lmax)
xclx = sh.SHCoeffs.from_zeros(lmax,'complex')
for l in range(0, lmax+1):
for m in range(-l, l+1):
tmp = SHdecomp(fvalue,area,fangle,l,m)
xre.set_coeffs(tmp[0], l, m)
xclx.set_coeffs(tmp[1], l, m)
result = collections.namedtuple('result', 'real, complex')
return result(real = xre,complex=xclx)
ts = spheregrid(nlat=10,nlon=10)
spheretriplot(ts)
f = randSHcoef(50)
fvalV = SHval(ts.vangles,f.coeffs).real
fvalF = SHval(ts.fangles,f.coeffs).real
l = 2
m = 1
lmax = 10
fakefvalF = np.random.randn(ts.area.size)
print SHdecomp(fakefvalF,ts.area,ts.fangles,l,m)
dcreal = SHdecomp_lmax(fakefvalF,ts.area,ts.fangles,lmax).real
dcclx = SHdecomp_lmax(fakefvalF,ts.area,ts.fangles,lmax).complex
print dcreal.coeffs
print dcclx.coeffs
alpha = math.pi/6
beta = math.pi/4
gamma = math.pi/3
- これのよいところは、球を回転させた後の球面調和関数係数を、x.rotate(a,b,c)とするだけでpyshtoolsの関数で計算できること
dcreal_rot = dcreal.rotate(alpha,beta,gamma)
dcclx_rot = dcclx.rotate(alpha,beta,gamma)
print dcreal_rot.coeffs
print dcclx_rot.coeffs
- 回転によって、分解係数の二乗ノルムは変わらない。また、lごとの係数二乗ノルムも変わらない
print "REAL"
print "all"
print np.sum(np.power(dcreal.coeffs,2))
print np.sum(np.power(dcreal_rot.coeffs,2))
print "--"
for i in range(lmax+1):
print i
print np.sum(np.power(dcreal.coeffs[0,i,],2)+np.power(dcreal.coeffs[1,i,],2))
print np.sum(np.power(dcreal_rot.coeffs[0,i,],2)+np.power(dcreal_rot.coeffs[1,i,],2))
print "--"
print "COMPLEX"
print "all"
print np.sum(np.power(abs(dcclx.coeffs),2))
print np.sum(np.power(abs(dcclx_rot.coeffs),2))
print "--"
for i in range(lmax+1):
print i
print np.sum(np.power(abs(dcclx.coeffs[0,i,]),2)+np.power(abs(dcclx.coeffs[1,i,]),2))
print np.sum(np.power(abs(dcclx_rot.coeffs[0,i,]),2)+np.power(abs(dcclx_rot.coeffs[1,i,]),2))
- sympyによる球面調和関数の回転変換
- 球面調和関数で表されるものには物理・量子物理の電子の状態などがある。それもあってscipyに球面調和関数のハンドリング関数があるのだが、from sympy.physics.quantum にも、そんなのがある
- sympyは代数処理(変数を持った式を扱う仕組み。いちいち数値計算しないで、式変形をする仕組み。必要ならば、式変形の最後に式を評価する)
- 分解係数の回転にあたってClebsch-Goradn係数というのがある。これは係数の回転変換に使うWignerDの相方のようなもので、階乗のおばけのようなもので面倒くさいし、うまくすれば割り算などが式変形でなくせる
- それを使った関数を作って見る
def vl1l2jk(l1,l2,j,k,coef):
ret = 0
for m in range(-l1,l1+1):
if np.abs(k-m) <= l2:
if m < 0:
tmp1 = coef[1,l1,-m]
else:
tmp1 = coef[0,l1,m]
if k-m < 0:
tmp2 = coef[1,l2,-k+m]
else:
tmp2 = coef[0,l2,k-m]
ret += CG(l1,m,l2,k-m,j,k) * tmp1 * tmp2
else:
ret += 0
return ret
def vl1l2vl3l4j(l1,l2,l3,l4,j,coef):
ret =0
for k in range(-j,j+1):
ret += (-1)**(j-k)*vl1l2jk(l1,l2,j,k,coef)*vl1l2jk(l3,l4,j,-k,coef)
ret /= np.sqrt(2*j+1)
return ret
def vl1l2jv(l1,l2,j,coef):
ret = 0
for k in range(-j,j+1):
if (-k) <0:
tmp = coef[1,l2,k]
else:
tmp = coef[0,l2,-k]
ret += (-1)**(j-k)*vl1l2jk(l1,l2,j,k,coef)*tmp
ret /= np.sqrt(2*j+1)
return ret
l1 = 1
l2 = 1
j = 0
k = 0
print vl1l2jk(l1,l2,j,k,dcclx.coeffs)
print vl1l2jk(l1,l2,j,k,dcclx_rot.coeffs)
print vl1l2jk(l1,l2,j,k,dcclx.coeffs).doit().evalf()
print vl1l2jk(l1,l2,j,k,dcclx_rot.coeffs).doit().evalf()
print vl1l2jk(l1,l2,j,k,dcreal.coeffs)
print vl1l2jk(l1,l2,j,k,dcreal_rot.coeffs)
print vl1l2jk(l1,l2,j,k,dcreal.coeffs).doit().evalf()
print vl1l2jk(l1,l2,j,k,dcreal_rot.coeffs).doit().evalf()