12

周期的な境界条件を考慮しながら、3D 空間内の 2 点間の距離を計算する Python スクリプトを作成しました。問題は、この計算を非常に多くの点に対して行う必要があり、計算が非常に遅いことです。これが私の機能です。

def PBCdist(coord1,coord2,UC):
    dx = coord1[0] - coord2[0]
    if (abs(dx) > UC[0]*0.5):
       dx = UC[0] - dx
    dy = coord1[1] - coord2[1]
    if (abs(dy) > UC[1]*0.5):
       dy = UC[1] - dy
    dz = coord1[2] - coord2[2]
    if (abs(dz) > UC[2]*0.5):
       dz = UC[2] - dz
    dist = np.sqrt(dx**2 + dy**2 + dz**2)
    return dist

次に、関数を次のように呼び出します

for i, coord2 in enumerate(coordlist):
  if (PBCdist(coord1,coord2,UC) < radius):
      do something with i

最近、リスト内包表記を使用するとパフォーマンスが大幅に向上するという記事を読みました。以下は、非 PBC ケースでは機能しますが、PBC ケースでは機能しません

coord_indices = [i for i, y in enumerate([np.sqrt(np.sum((coord2-coord1)**2)) for coord2 in coordlist]) if y < radius]
for i in coord_indices:
   do something

PBCの場合にこれと同等のことを行う方法はありますか? よりうまく機能する代替手段はありますか?

4

3 に答える 3

15

distance()5711 ポイントのループをベクトル化できるように関数を記述する必要があります。x0次の実装では、点の配列をまたはx1パラメータとして受け入れます。

def distance(x0, x1, dimensions):
    delta = numpy.abs(x0 - x1)
    delta = numpy.where(delta > 0.5 * dimensions, delta - dimensions, delta)
    return numpy.sqrt((delta ** 2).sum(axis=-1))

例:

>>> dimensions = numpy.array([3.0, 4.0, 5.0])
>>> points = numpy.array([[2.7, 1.5, 4.3], [1.2, 0.3, 4.2]])
>>> distance(points, [1.5, 2.0, 2.5], dimensions)
array([ 2.22036033,  2.42280829])

結果は、 の 2 番目のパラメータとして渡されたポイントdistance()と の各ポイントの間の距離の配列ですpoints

于 2012-06-19T20:58:26.580 に答える
6
import numpy as np

bounds = np.array([10, 10, 10])
a = np.array([[0, 3, 9], [1, 1, 1]])
b = np.array([[2, 9, 1], [5, 6, 7]])

min_dists = np.min(np.dstack(((a - b) % bounds, (b - a) % bounds)), axis = 2)
dists = np.sqrt(np.sum(min_dists ** 2, axis = 1))

ここaに とbの間の距離を計算したいベクトルのリストがありbounds、 は空間の境界です (したがって、ここでは 3 つの次元すべてが 0 から 10 になり、ラップします)。a[0]b[0]a[1]および などの間の距離を計算b[1]します。

numpy の専門家はもっとうまくやれると確信していますが、ほとんどの作業は現在 C で行われているため、これはおそらくあなたがやっていることよりも桁違いに速いでしょう.

于 2012-06-19T20:52:15.400 に答える
0

meshgrid距離を生成するのに非常に役立つことがわかりました。例えば:

import numpy as np
row_diff, col_diff = np.meshgrid(range(7), range(8))
radius_squared = (row_diff - x_coord)**2 + (col_diff - y_coord)**2

radius_squaredこれで、すべてのエントリが配列位置からの距離の 2 乗を指定する array( ) ができました[x_coord, y_coord]

配列を循環化するには、次のようにします。

row_diff, col_diff = np.meshgrid(range(7), range(8))
row_diff = np.abs(row_diff - x_coord)
row_circ_idx = np.where(row_diff > row_diff.shape[1] / 2)
row_diff[row_circ_idx] = (row_diff[row_circ_idx] - 
                         2 * (row_circ_idx + x_coord) + 
                         row_diff.shape[1])
row_diff = np.abs(row_diff)
col_diff = np.abs(col_diff - y_coord)
col_circ_idx = np.where(col_diff > col_diff.shape[0] / 2)
col_diff[row_circ_idx] = (row_diff[col_circ_idx] - 
                         2 * (col_circ_idx + y_coord) + 
                         col_diff.shape[0])
col_diff = np.abs(row_diff)
circular_radius_squared = (row_diff - x_coord)**2 + (col_diff - y_coord)**2

これで、すべての配列距離がベクトル演算で循環化されました。

于 2014-11-21T17:35:34.220 に答える