Вещание / Векторизация внутреннего и внешнего цикла в python / NumPy - PullRequest
0 голосов
/ 28 марта 2020

Цель

Я превратил двойной for loop в один for loop, используя vectorization. Теперь я хотел бы избавиться от последних loop.

Я хочу slice * Nx3 array координат и рассчитать расстояния между нарезанной частью и оставшейся частью без используя для l oop.

Два случая

(1) срез всегда равен 3x3.

(2) срез является переменным, т. Е. Mx3, где М всегда значительно меньше, чем N

Векторизация взаимодействия 1 строки среза, взаимодействующей с остатком, проста. Тем не менее, я застрял, используя для цикла l oop, чтобы сделать (в случае среза размером 3) 3 цикла, чтобы вычислить все расстояния.

Контекст:

Массив Nx3 это координаты атома, срез - это все атомы в определенной молекуле c. Я хочу рассчитать энергию данной молекулы, взаимодействующей с остальной системой. Первым шагом является вычисление расстояний между каждым атомом в молекуле, со всеми другими атомами. Вторая часть состоит в том, чтобы использовать эти расстояния в функции для вычисления энергии, и это выходит за рамки этого вопроса.

Вот то, что у меня есть для рабочего минимального примера (у меня есть vectorized внутренний l oop, но нужно (очень хотелось бы ...) vectorize outer loop. Что l oop не всегда будет иметь только размер 3, а python медленный для циклов.

Минимальный рабочий пример

import numpy as np 

box=10 # simulation box is size 10 for this example
r = np.random.rand(1000,3) * box  # avoids huge numbers later by scaling  coords

start=0 #fixed starting index for example (first atom)
end=2   #fixed ending index for example   (last atom)

rj=np.delete(r, np.arange(start,end), 0)
ri = r[np.arange(start,end),:]

atoms_in_molecule, coords = np.shape(ri)
energy = 0
for a in range(atoms_in_molecule):
    rij = ri[a,:] - rj                # I want to get rid of this 'a' index dependance
    rij = rij - np.rint(rij/box)*box  # periodic boundary conditions - necessary
    rij_sq = np.sum(rij**2,axis=1)

    # perform energy calculation using rij_sq
    ener = 4 * ((1/rij_sq)**12 - (1/rij_sq)**6)  # dummy LJ, do not optimize
    energy += np.sum(ener)

print(energy)

Этот вопрос не касается оптимизации векторизации, которая у меня уже есть. Я поиграл с pdist / cdist и другими. Все, что я хочу, это избавиться от досадно за l oop над атомами. Остальное я оптимизирую.

1 Ответ

1 голос
/ 29 марта 2020

Вот как вы можете это сделать:

R = ri[:,None] - rj[None, :]
R = R - np.rint(R/box)*box
R_sq = np.sum(np.square(R), axis=2)

energy = np.sum(4 * ((1/R_sq)**12 - (1/R_sq)**6))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...