Sie können die Tatsache nutzen, dass Sie wissen, dass Ihr Koordinatenfeld immer (N,3)
in Form ist, so dass Sie eine Array-Erstellung und Aufruf np.dot
loswerden können, die für wirklich kleine Arrays wie die hier weniger effizient ist. so tun, ich habe Ihre Funktion als abs_contact_order2
neu geschrieben:
from __future__ import print_function, division
import mdtraj as md
import numpy as np
import numba as nb
@nb.njit
def abs_contact_order(xyz, atoms_residue, cutoff_nm=.6):
"""Return the absolute contact order."""
contact_count = 0
seq_distance_sum = 0
cutoff_2 = cutoff_nm*cutoff_nm
N = len(atoms_residue)
for i in xrange(N):
for j in xrange(N):
seq_dist = atoms_residue[j] - atoms_residue[i]
if seq_dist > 0:
d = xyz[j] - xyz[i]
if np.dot(d, d) < cutoff_2:
seq_distance_sum += seq_dist
contact_count += 1
if contact_count==0.:
return 0.
return seq_distance_sum/float(contact_count)
@nb.njit
def abs_contact_order2(xyz, atoms_residue, cutoff_nm=.6):
"""Return the absolute contact order."""
contact_count = 0
seq_distance_sum = 0
cutoff_2 = cutoff_nm*cutoff_nm
N = len(atoms_residue)
for i in xrange(N):
for j in xrange(N):
seq_dist = atoms_residue[j] - atoms_residue[i]
if seq_dist > 0:
d = 0.0
for k in xrange(3):
d += (xyz[j,k] - xyz[i,k])**2
if d < cutoff_2:
seq_distance_sum += seq_dist
contact_count += 1
if contact_count==0.:
return 0.
return seq_distance_sum/float(contact_count)
Und dann Timings:
%timeit abs_co = abs_contact_order(traj.xyz[0], seq_atoms, cutoff_nm=0.60)
1 loop, best of 3: 723 ms per loop
%timeit abs_co = abs_contact_order2(traj.xyz[0], seq_atoms, cutoff_nm=0.60)
10 loops, best of 3: 28.2 ms per loop
ich die print-Anweisungen aus den Funktionen übernommen haben, die Sie laufen zu lassen Numba Jit in nopython
Modus. Wenn Sie diese Informationen wirklich benötigen, gebe ich alle erforderlichen Daten zurück und schreibe einen dünnen Wrapper, der die Rückgabewerte prüft und Debug-Informationen nach Bedarf ausgibt.
Beachten Sie auch, dass Sie beim Timing von Numba-Funktionen zuerst den Jit "aufwärmen" sollten, indem Sie die Funktion außerhalb der Timing-Schleife aufrufen. Wenn Sie die Funktion oft aufrufen, ist die Zeit, die Numba benötigt, um die Funktion zu verwenden, größer als die Zeit für einen einzelnen Anruf, so dass Sie nicht wirklich einen guten Hinweis darauf erhalten, wie schnell der Code ist. Wenn Sie jedoch die Funktion nur einmal aufrufen und die Startzeit wichtig ist, setzen Sie die Zeitmessung so fort, wie Sie sind.
Update:
Sie können dies auf ein wenig weiter beschleunigen, da Sie Schleifen über (i, j) und (j, i) Paare und sie sind symmetrisch:
@nb.njit
def abs_contact_order3(xyz, atoms_residue, cutoff_nm=.6):
"""Return the absolute contact order."""
contact_count = 0
seq_distance_sum = 0
cutoff_2 = cutoff_nm*cutoff_nm
N = len(atoms_residue)
for i in xrange(N):
for j in xrange(i+1,N):
seq_dist = atoms_residue[j] - atoms_residue[i]
if seq_dist > 0:
d = 0.0
for k in xrange(3):
d += (xyz[j,k] - xyz[i,k])**2
if d < cutoff_2:
seq_distance_sum += 2*seq_dist
contact_count += 2
if contact_count==0.:
return 0.
return seq_distance_sum/float(contact_count)
und timing:
%timeit abs_co = abs_contact_order3(traj.xyz[0], seq_atoms, cutoff_nm=0.60)
100 loops, best of 3: 15.7 ms per loop
Auch ich konnte kein Tag für mdtraj hinzufügen, was eine Schande ist. – Ajasja
Zu nahe Wähler: Zu breit? Es ist vielleicht etwas daneben, aber nicht zu breit. – Ajasja
Ich denke, wenn Sie Ihre eigene Antwort in der Frage als etwas, das Sie in der ursprünglichen Frage versuchten, haben würde, wäre die Frage als weniger breit und zugänglicher für Menschen, die Ihnen aushelfen. – JoshAdel