简体   繁体   English

用Python编写的Friends-of-friends算法必须在Fortran 90/95中

[英]Friends-of-friends algorithm written in Python need to be in Fortran 90/95

I'm trying to write my own code for a 'friends-of-friends' algorithm. 我正在尝试为“朋友的”算法编写自己的代码。 This algorithm acts on a set of 3d data points and returns the number of 'halos' in the dataset. 该算法作用于一组3d数据点,并返回数据集中的“晕轮”数。 Each halo is a collection of point whose distance is less than the linking length, b, the only parameter of the program. 每个光环都是点的集合,其距离小于链接长度b,即程序的唯一参数。

Algorithmic Description: The FOF algorithm has a single free parameter called the linking length. 算法说明:FOF算法具有单个自由参数,称为链接长度。 Any two particles that are separated by a distance less than or equal to the linking length are called "friends". 间隔小于或等于链接长度的任何两个粒子称为“朋友”。 The FOF group is then defined by the set of particles for which each particle within the set is connected to every other particle in the set through a network of friends. 然后,FOF组由一组粒子定义,对于该粒子集,集合中的每个粒子都通过朋友网络连接到集合中的每个其他粒子。

Set FOF group counter j=1. 设置FOF组计数器j = 1。

  • For each particle, n, not yet associated with any group: 对于每个尚未与任何组关联的粒子n:

  • Assign n to group j, initialize a new member list, mlist, for group j with particle n as first entry, 将n分配给组j,为组j初始化一个新的成员列表mlist,以粒子n作为第一个条目,

  • Recursively, for each new particle p in mlist: 递归地,对于mlist中的每个新粒子p:

  • Find neighbors of p lying within a distance less than or equal to the linking length, add to mlist those not already assigned to group j, 查找距离小于或等于链接长度的p的邻居,将尚未分配给组j的邻居添加到mlist,
  • Record mlist for group j, set j=j+1. 记录组j的mlist,设置j = j + 1。

This is my attempt to code the algorithm. 这是我对算法进行编码的尝试。 The only language I'm comfortable in doing this is Python. 我唯一能做到这一点的语言是Python。 However, I need this code to be written in Fortran or make it faster. 但是,我需要将此代码用Fortran编写或使其更快。 I really hope someone would help me. 我真的希望有人能帮助我。

First I generate a set of points that should mimic the presence of 3 halos: 首先,我生成一组点,这些点应模仿3个光环的存在:

import random
from random import *
import math
from math import *
import numpy
from numpy import *
import time

points = 1000

halos=[0,100.,150.]

x=[]
y=[]
z=[]
id=[]
for i in arange(0,points,1):
   x.append(halos[0]+random())
   y.append(halos[0]+random())
   z.append(halos[0]+random())
   id.append(i)

for i in arange(points,points*2,1):
   x.append(halos[1]+random())
   y.append(halos[1]+random())
   z.append(halos[1]+random())
   id.append(i)

for i in arange(points*2,points*3,1):
   x.append(halos[2]+random())
   y.append(halos[2]+random())
   z.append(halos[2]+random())
   id.append(i)

Then I coded the FOF algorithm: 然后,我对FOF算法进行了编码:

  x=array(x)
  y=array(y)
  z=array(z)
  id=array(id)

  t0 = time.time()                         

  id_grp=[]
  groups=zeros((len(x),1)).tolist()
  particles=id
  b=1 # linking length
  while len(particles)>0:
  index = particles[0]
  # remove the particle from the particles list
  particles.remove(index)
  groups[index]=[index]
  print "#N ", index
  dx=x-x[index]
  dy=y-y[index]
  dz=z-z[index]
  dr=sqrt(dx**2.+dy**2.+dz**2.)
  id_to_look = where(dr<b)[0].tolist()
  id_to_look.remove(index)
  nlist = id_to_look
  # remove all the neighbors from the particles list
  for i in nlist:
        if (i in particles):
           particles.remove(i)
  print "--> neighbors", nlist
  groups[index]=groups[index]+nlist
  new_nlist = nlist
  while len(new_nlist)>0:
          index_n = new_nlist[0]
          new_nlist.remove(index_n)
          print "----> neigh", index_n
          dx=x-x[index_n]
          dy=y-y[index_n]
          dz=z-z[index_n]
          dr=sqrt(dx**2.+dy**2.+dz**2.)
          id_to_look = where(dr<b)[0].tolist()
          id_to_look = list(set(id_to_look) & set(particles))
          nlist = id_to_look
          if (len(nlist)==0):
             print "No new neighbors found"
          else:
             groups[index]=groups[index]+nlist
             new_nlist=new_nlist+nlist
             print "------> neigh-neigh", new_nlist
             for k in nlist:
               particles.remove(k)

At the end one ends up with a list of the halos in the list groups 最后,列出列表groups中的光环

This part of the code is a bit off topic but I thought it would be nice to show it to you. 这部分代码与主题无关,但是我认为向您展示它会很不错。 I am basically deleting all the groups with no particles, sorting them according to the number of particles and showing some properties. 我基本上是删除所有没有粒子的组,根据粒子的数量对它们进行排序并显示一些属性。

  def select(test,list):
  selected = []
  for item in list:
    if test(item) == True:
      selected.append(item)
  return selected

  groups=select(lambda x: sum(x)>0.,groups)
  # sorting groups
  groups.sort(lambda x,y: cmp(len(x),len(y)))
  groups.reverse()

  print time.time() - t0, "seconds"

  mass=x
  for i in arange(0,len(groups),1):
    total_mass=sum([mass[j] for j in groups[i]])
    x_cm = sum([mass[j]*x[j] for j in groups[i]])/total_mass
    y_cm = sum([mass[j]*y[j] for j in groups[i]])/total_mass
    z_cm = sum([mass[j]*z[j] for j in groups[i]])/total_mass
    dummy_x_cm = [x[j]-x_cm for j in groups[i]]
    dummy_y_cm = [y[j]-y_cm for j in groups[i]]
    dummy_z_cm = [z[j]-z_cm for j in groups[i]]
    dummy_x_cm = array(dummy_x_cm)
    dummy_y_cm = array(dummy_y_cm)
    dummy_z_cm = array(dummy_z_cm)
    dr = max(sqrt(dummy_x_cm**2.+dummy_y_cm**2.+dummy_z_cm**2.))
    dummy_x_cm = max(dummy_x_cm)
    dummy_y_cm = max(dummy_y_cm)
    dummy_z_cm = max(dummy_z_cm)
    print i, len(groups[i]), x_cm, y_cm, z_cm,dummy_x_cm,dummy_y_cm,dummy_z_cm

I think that you would be ill-advised to start off learning Fortran in the hope that the resulting code will be faster than your current implementation. 我认为您不明智地开始学习Fortran,希望生成的代码比您当前的实现更快。 It may, eventually, be, but I think you would be better advised to make your Python implementation as fast as you can before thinking of implementing in another language, especially a foreign language. 最终可能会这样,但是我认为最好在考虑使用另一种语言(尤其是外语)之前,使您的Python实现尽可能快。

I write Fortran, and personally I think its performance pisses all over Python, but people who know about these things provide compelling arguments that Python+SciPy+Numpy can, if carefully crafted, match Fortran for speed in the computational kernels of many scientific/engineering programs. 我写了Fortran,就我个人而言,我认为它的性能在整个Python上都很差,但是了解这些内容的人提出了令人信服的论点,如果精心设计,Python + SciPy + Numpy可以在许多科学/工程学的计算内核中与Fortran相提并论。程式。 Don't forget that you haven't optimised your Python until all the cores on your computer are running red hot. 不要忘记,直到计算机上的所有内核都开始运行之前,您还没有优化Python。

So: 所以:

1st - get a working implementation in Python. 1-在Python中获得可行的实现。

2nd - make your implementation as fast as possible. 第二-使您的实施尽快。

IF (capital letters because it's a big 'if') the code is still not fast enough and the cost/benefit of translating it to a compiled language is favourable THEN consider which compiled language to translate it in to. 如果IF(大写的“ if”,大写字母)仍然不够快,并且将其翻译为编译语言的成本/收益是有利的,然后考虑将其翻译成哪种编译语言。 If you are in a field where Fortran is widely used, then learn Fortran by all means, but it is something of a niche language and it may benefit your career more to learn C++ or one of its relatives. 如果您在Fortran广泛使用的领域,则一定要学习Fortran,但这是一种小众语言,学习C ++或其亲戚之一可能会使您的职业受益更多。

EDIT (too long to fit in the comment box) 编辑 (太长,无法容纳在评论框中)

Why mislead us in your question ? 为什么在您的问题上误导我们? You state that the only language you are comfortable with is Python, now you say that you know Fortran. 您声明自己最喜欢的语言是Python,现在您说您知道Fortran。 I guess you must be uncomfortable with it. 我想您一定对此感到不舒服。 And, from your comment, it seems that maybe the help you really need is in making your Python implementation faster; 而且,根据您的评论,似乎您真正需要的帮助可能是使Python实现更快。 Sideshow Bob has offered some advice. 杂耍节目Bob提供了一些建议。 Take that into consideration, then parallelise. 考虑到这一点,然后并行化。

If you have a modern graphics card you can paralelize to hundreds of processors (depending on your card) in Python code using PyOpenCL . 如果您有现代显卡,则可以使用PyOpenCL用Python代码并行化成数百个处理器(取决于您的显卡)。

You can investigate to see if the algoritm FoF is implemented inside this voidfinder F90 code 您可以调查一下是否在此voidfinder F90代码内实现了算法FoF

You can define distance as the squared distance to avoid the use of sqrt() and use x*x instead of x**2... 您可以将距离定义为平方距离以避免使用sqrt()并使用x * x而不是x ** 2 ...

A pointer towards a more efficient algorithm. 指向更有效算法的指针。 If I am not mistaken you are comparing a point to every other point to see if any are closer than the linking length. 如果我没记错的话,您正在将一个点与其他每个点进行比较,以查看是否有点比链接长度更近。 For large numbers of points there are quicker ways of finding a near neighbours - spatial indexing and KD trees off the top of my head but doubtless there are other methods too that will work for you. 对于大量的点,有更快的方法来查找附近的邻居-空间索引和KD树不在我的头上,但是毫无疑问,还有其他方法也可以为您服务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM