簡體   English   中英

用Python編寫的Friends-of-friends算法必須在Fortran 90/95中

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

我正在嘗試為“朋友的”算法編寫自己的代碼。 該算法作用於一組3d數據點,並返回數據集中的“暈輪”數。 每個光環都是點的集合,其距離小於鏈接長度b,即程序的唯一參數。

算法說明:FOF算法具有單個自由參數,稱為鏈接長度。 間隔小於或等於鏈接長度的任何兩個粒子稱為“朋友”。 然后,FOF組由一組粒子定義,對於該粒子集,集合中的每個粒子都通過朋友網絡連接到集合中的每個其他粒子。

設置FOF組計數器j = 1。

  • 對於每個尚未與任何組關聯的粒子n:

  • 將n分配給組j,為組j初始化一個新的成員列表mlist,以粒子n作為第一個條目,

  • 遞歸地,對於mlist中的每個新粒子p:

  • 查找距離小於或等於鏈接長度的p的鄰居,將尚未分配給組j的鄰居添加到mlist,
  • 記錄組j的mlist,設置j = j + 1。

這是我對算法進行編碼的嘗試。 我唯一能做到這一點的語言是Python。 但是,我需要將此代碼用Fortran編寫或使其更快。 我真的希望有人能幫助我。

首先,我生成一組點,這些點應模仿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)

然后,我對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)

最后,列出列表groups中的光環

這部分代碼與主題無關,但是我認為向您展示它會很不錯。 我基本上是刪除所有沒有粒子的組,根據粒子的數量對它們進行排序並顯示一些屬性。

  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

我認為您不明智地開始學習Fortran,希望生成的代碼比您當前的實現更快。 最終可能會這樣,但是我認為最好在考慮使用另一種語言(尤其是外語)之前,使您的Python實現盡可能快。

我寫了Fortran,就我個人而言,我認為它的性能在整個Python上都很差,但是了解這些內容的人提出了令人信服的論點,如果精心設計,Python + SciPy + Numpy可以在許多科學/工程學的計算內核中與Fortran相提並論。程式。 不要忘記,直到計算機上的所有內核都開始運行之前,您還沒有優化Python。

所以:

1-在Python中獲得可行的實現。

第二-使您的實施盡快。

如果IF(大寫的“ if”,大寫字母)仍然不夠快,並且將其翻譯為編譯語言的成本/收益是有利的,然后考慮將其翻譯成哪種編譯語言。 如果您在Fortran廣泛使用的領域,則一定要學習Fortran,但這是一種小眾語言,學習C ++或其親戚之一可能會使您的職業受益更多。

編輯 (太長,無法容納在評論框中)

為什么在您的問題上誤導我們? 您聲明自己最喜歡的語言是Python,現在您說您知道Fortran。 我想您一定對此感到不舒服。 而且,根據您的評論,似乎您真正需要的幫助可能是使Python實現更快。 雜耍節目Bob提供了一些建議。 考慮到這一點,然后並行化。

如果您有現代顯卡,則可以使用PyOpenCL用Python代碼並行化成數百個處理器(取決於您的顯卡)。

您可以調查一下是否在此voidfinder F90代碼內實現了算法FoF

您可以將距離定義為平方距離以避免使用sqrt()並使用x * x而不是x ** 2 ...

指向更有效算法的指針。 如果我沒記錯的話,您正在將一個點與其他每個點進行比較,以查看是否有點比鏈接長度更近。 對於大量的點,有更快的方法來查找附近的鄰居-空間索引和KD樹不在我的頭上,但是毫無疑問,還有其他方法也可以為您服務。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM