241 lines
7.4 KiB
Python
241 lines
7.4 KiB
Python
from __future__ import print_function, absolute_import, division
|
|
|
|
__all__ = ['Particles', 'inv_distance', 'log_distance']
|
|
|
|
import numpy as np
|
|
from time import time
|
|
from numba import jit
|
|
import math
|
|
import cmath
|
|
from scipy import integrate as intg
|
|
|
|
|
|
def log_dist_int(x,y):
|
|
return -1 / (2 * np.pi) * np.log(np.sqrt(x ** 2 + y ** 2))
|
|
def log_dist_2d(xd,yd):
|
|
return -1 / (2 * np.pi) * np.log(np.sqrt((xd[0] - yd[0]) ** 2 + (xd[1] - yd[1]) ** 2))
|
|
def log_distance(data1, list1, data2, list2):
|
|
ans = np.ndarray((list1.size, list2.size), dtype=np.float64)
|
|
vertex1 = data1.vertex
|
|
vertex2 = data2.vertex
|
|
n = list1.size
|
|
m = list2.size
|
|
N = data1.vertex.shape[1]
|
|
for i in range(n):
|
|
for j in range(m):
|
|
if (vertex1[:,list1[i]] == vertex2[:,list2[j]]).all():
|
|
ans[i, j] = intg.dblquad(log_dist_int,0,1/(2*np.sqrt(N)),lambda x: 0, lambda x: 1/(2*np.sqrt(N)))[0]*4
|
|
else:
|
|
ans[i, j] = log_dist_2d(vertex1[:,list1[i]],vertex2[:,list2[j]])/N
|
|
return ans
|
|
|
|
###############################################################################
|
|
### interactions for Particles ###
|
|
###############################################################################
|
|
|
|
def inv_distance(data1, list1, data2, list2):
|
|
"""
|
|
Returns 1/r for each pair of particles from two sets.
|
|
|
|
Function 1/r is used as interaction between two particles.
|
|
|
|
Parameters
|
|
----------
|
|
data1 : Python object
|
|
Destination of interactions
|
|
list1 : array
|
|
Indices of particles from `data1` to compute interactions
|
|
data2 : Python object
|
|
Source of interactions
|
|
list2 : array
|
|
Indices of particles from `data1` to compute interactions
|
|
|
|
Returns
|
|
-------
|
|
numpy.ndarray(ndim=2)
|
|
Array of interactions of corresponding particles.
|
|
"""
|
|
ans = np.ndarray((list1.size, list2.size), dtype=np.float64)
|
|
return inv_distance_numba(data1.ndim, data1.vertex, list1, data2.vertex,
|
|
list2, ans)
|
|
|
|
@jit(nopython=True, parallel=True)
|
|
def inv_distance_numba(ndim, vertex1, list1, vertex2, list2, ans):
|
|
n = list1.size
|
|
m = list2.size
|
|
for i in range(n):
|
|
for j in range(m):
|
|
tmp_l = 0.0
|
|
for k in range(ndim):
|
|
tmp_v = vertex1[k, list1[i]]-vertex2[k, list2[j]]
|
|
tmp_l += tmp_v*tmp_v
|
|
if tmp_l <= 0:
|
|
ans[i, j] = 0
|
|
else:
|
|
ans[i, j] = 1./math.sqrt(tmp_l)
|
|
return ans
|
|
|
|
def log_distance_h2t(data1, list1, data2, list2):
|
|
"""
|
|
Returns -log(r) for each pair of particles from two sets.
|
|
|
|
Function -log(r) is used as interaction between two particles.
|
|
|
|
Parameters
|
|
----------
|
|
data1 : Python object
|
|
Destination of interactions
|
|
list1 : array
|
|
Indices of particles from `data1` to compute interactions
|
|
data2 : Python object
|
|
Source of interactions
|
|
list2 : array
|
|
Indices of particles from `data1` to compute interactions
|
|
|
|
Returns
|
|
-------
|
|
numpy.ndarray(ndim=2)
|
|
Array of interactions of corresponding particles.
|
|
"""
|
|
ans = np.ndarray((list1.size, list2.size), dtype=np.float64)
|
|
return log_distance_numba(data1.ndim, data1.vertex, list1, data2.vertex,
|
|
list2, ans)
|
|
|
|
@jit(nopython=True)
|
|
def log_distance_numba(ndim, vertex1, list1, vertex2, list2, ans):
|
|
n = list1.size
|
|
m = list2.size
|
|
for i in range(n):
|
|
for j in range(m):
|
|
tmp_l = 0.0
|
|
for k in range(ndim):
|
|
tmp_v = vertex1[k, list1[i]]-vertex2[k, list2[j]]
|
|
tmp_l += tmp_v*tmp_v
|
|
if tmp_l <= 0:
|
|
ans[i, j] = 0
|
|
else:
|
|
ans[i, j] = -0.5*math.log(tmp_l)
|
|
if list1[i] == list2[j]:
|
|
ans[i, j] = 15
|
|
return ans
|
|
|
|
def exp_distance_h2t(data1, list1, data2, list2):
|
|
ans = np.ndarray((list1.size, list2.size), dtype=np.cdouble)
|
|
return exp_distance_numba(data1.ndim, data1.vertex, list1, data2.vertex,
|
|
list2, data1.k, ans)
|
|
|
|
@jit(nopython=True)
|
|
def exp_distance_numba(ndim, vertex1, list1, vertex2, list2, kz, ans):
|
|
n = list1.size
|
|
m = list2.size
|
|
for i in range(n):
|
|
for j in range(m):
|
|
tmp_l = 0.0
|
|
for k in range(ndim):
|
|
tmp_v = vertex1[k, list1[i]] - vertex2[k, list2[j]]
|
|
tmp_l += tmp_v*tmp_v
|
|
if tmp_l <= 0:
|
|
ans[i, j] = 0
|
|
else:
|
|
r = math.sqrt(tmp_l)
|
|
ans[i, j] = cmath.exp(1j * kz * r)/ r
|
|
if list1[i] == list2[j]:
|
|
ans[i, j] = 6 + 1j*0
|
|
return ans
|
|
|
|
# def test_fun(data1, list1, data2, list2):
|
|
# ans = np.ndarray((list1.size, list2.size), dtype=np.float64)
|
|
# # ans = np.ndarray((list1.size, list2.size), dtype=np.float64)
|
|
# return test_fun_numba(data1.ndim, data1.vertex, list1, data2.vertex,
|
|
# list2, ans)
|
|
|
|
# @jit(nopython=True)
|
|
# def test_fun_numba(ndim, vertex1, list1, vertex2, list2, ans):
|
|
# n = list1.size
|
|
# m = list2.size
|
|
# for i in range(n):
|
|
# for j in range(m):
|
|
# tmp_l = 0.0
|
|
# for k in range(ndim):
|
|
# tmp_v = vertex1[k, list1[i]]-vertex2[k, list2[j]]
|
|
# tmp_l += tmp_v*tmp_v
|
|
# if tmp_l <= 0:
|
|
# ans[i, j] = 0
|
|
# else:
|
|
# # r = math.sqrt(tmp_l)
|
|
# ans[i, j] = 1./ (tmp_l)
|
|
# if list1[i] == list2[j]:
|
|
# ans[i, j] = 1000
|
|
# return ans
|
|
|
|
|
|
def double_layer(data1, list1, data2, list2):
|
|
ans = np.ndarray((list1.size, list2.size), dtype=np.cdouble)
|
|
return double_layer_numba(data1.ndim, data1.vertex, list1, data2.vertex,
|
|
list2, data1.k, data1.norms, ans)
|
|
|
|
@jit(nopython=True)
|
|
def double_layer_numba(ndim, vertex1, list1, vertex2, list2, kz, norms, ans):
|
|
n = list1.size
|
|
m = list2.size
|
|
for i in range(n):
|
|
for j in range(m):
|
|
tmp_l = 0.0
|
|
tetha = 0.0
|
|
len_norm = 0.0
|
|
for k in range(ndim):
|
|
tmp_v = vertex1[k, list1[i]] - vertex2[k, list2[j]]
|
|
tmp_l += tmp_v * tmp_v
|
|
tetha += tmp_v * norms[k,list1[i]]
|
|
len_norm += norms[k,list1[i]] * norms[k,list1[i]]
|
|
# print (tetha)
|
|
if tmp_l <= 0:
|
|
ans[i, j] = 0
|
|
else:
|
|
r = math.sqrt(tmp_l)
|
|
len_norm = math.sqrt(len_norm)
|
|
tetha = tetha / (r * len_norm)
|
|
ans[i, j] = (cmath.exp(1j * kz * r)/ r) * (1j * kz - 1/r)* math.cos(tetha)
|
|
if list1[i] == list2[j]:
|
|
ans[i, j] = 6 + 1j*0
|
|
return ans
|
|
|
|
@jit(nopython=True)
|
|
def comp_sph_numba(ndim, vertex1, list1, vertex2, list2, ans):
|
|
n = list1.size
|
|
m = list2.size
|
|
for i in range(n):
|
|
for j in range(m):
|
|
tmp_l = 0.0
|
|
for k in range(ndim):
|
|
tmp_v = vertex1[k, list1[i]]-vertex2[k, list2[j]]
|
|
tmp_l += tmp_v*tmp_v
|
|
if tmp_l <= 0:
|
|
ans[i, j] = 0
|
|
else:
|
|
ans[i, j] = 1/(4 * np.pi * math.sqrt(tmp_l))
|
|
if list1[i] == list2[j]:
|
|
ans[i, j] = 150
|
|
return ans
|
|
|
|
def comp_sph(data1, list1, data2, list2):
|
|
ans = np.ndarray((list1.size, list2.size))
|
|
return comp_sph_numba(data1.ndim, data1.vertex, list1, data2.vertex,
|
|
list2, ans)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|