How speed up this script?

I am using a script to calculate the vorticity at each particle using the surrounding particles and set the angular velocity to be used by the shaders… I iterate through each particle, and then filter a list of particles to those that are within a certain distance of the given particle, into a new list. Then use some cross products with all the particles in that list to get my angular velocity. Is there some better way to be doing this? When I have a lot of particles it gets very slow. Here is the script:

import bpyimport mathutils
import math
import threading




threads = 14.0


def calcav(p,ps):
    psorted = []
    M = p.size*5
    psl = list(filter(lambda q: (q.alive_state == 'ALIVE' and math.fabs(q.location[0]-p.location[0]) < M and math.fabs(q.location[1]-p.location[1]) < M and math.fabs(q.location[2]-p.location[2]) < M), ps))
    for q in psl:
        dist = (mathutils.Vector(q.location)- mathutils.Vector(p.location)).length
        if  dist < M and dist > 0 and len(psorted)<50:
            psorted.append(q)
            currentdist = dist
        
    angularvel = mathutils.Vector((0,0,0))
    if len(psorted)>0:
        for i in range(len(psorted)):
            angularvel +=  (mathutils.Vector(psorted[-1-i].location)- mathutils.Vector(p.location)).cross(mathutils.Vector(psorted[-1-i].velocity)- mathutils.Vector(p.velocity))/((mathutils.Vector(psorted[-1-i].location)- mathutils.Vector(p.location)).length**2)
        angularvel/= len(psorted)
        p.angular_velocity = (angularvel.x,angularvel.y,angularvel.z)
        
    del psorted[:]
    del psl[:]


def calclist(ps):
    print('Start')
    for p in ps:
        if p.alive_state == 'ALIVE':
            calcav(p,ps)
    print('Done')








def my_handler(scene):
    ps1 = bpy.context.scene.objects['SPH'].particle_systems[0]


    ts = []
    for i in range(int(threads)):
        lb = int(math.floor((i/threads)*len(ps1.particles)))
        print(lb)
        ub = int(math.floor(((i+1.0)/threads)*len(ps1.particles)))
        ts.append(threading.Thread(target= calclist, args=(ps1.particles[lb:ub],)))
        ts[-1].start()
        
    for t in ts:
        t.join()
    del ts[:]


def register():
    bpy.app.handlers.render_pre.append(my_handler)


def unregister():
    bpy.app.handlers.render_pre.remove(my_handler)


try:
    unregister()
except ValueError:
    pass
    
register()

cProfile is your friend…

Also couldn’t you pre compute or partially prefilter the alive particles in that psl list in calclist maybe?

Also don’t understand in the below code do you mean to just iterate over psorted? Why not just do that rather (i.e for p in psorted)? Furthermore it seems like in calcav you’re iterating over psorted twice which seems unnecessary:
for i in range(len(psorted)):
angularvel += (mathutils.Vector(psorted[-1-i].location)- mathutils.Vector(p.location)).cross(mathutils.Vector(psorted[-1-i].velocity)- mathutils.Vector(p.velocity))/((mathutils.Vector(psorted[-1-i].location)- mathutils.Vector(p.location)).length**2)

Helped me a couple of times:
https://wiki.python.org/moin/PythonSpeed/PerformanceTips

Thanks for the tips guys! I ended up figuring this out and may share it soon.