跳转至

N体问题的同学会

原文链接:https://www.nv5geospatialsoftware.com/Learn/Blogs/Blog-Details/an-n-body-college-reunion

9007 给本文评分:

5.0

N体问题的同学会

Jim Pendleton 2015年5月21日 星期四

大约30多年前,在我大二的量子力学课上,教授给我们布置了一项自由选题作业。我们可以用计算机解决任何物理问题,完全不必与量子力学相关,这对我来说正好,因为我从未完全理解过波函数。

在那个年代,为从事基础科学事业而受训的学生,都被期望懂得如何编写自己的分析应用,而不是盲目地点击电子表格或网页上的按钮。这在很大程度上是因为后者当时尚未被发明出来。

我选择了一个天体物理学问题。当时有关于简化星系碰撞的学术研究在进行,科学期刊上的那些图表让我着迷。N体问题远超出我的理解范围,除非N等于1或2。

我那时接触不到超级计算机,而我的经典力学训练也只停留在大一水平。

但我喜欢漂亮的图片。

那时候调试 Fortran PLOT10 程序颇具挑战性,因为你需要在校园计算中心排队等待额外的时间才能看到输出结果,而 Calcomp 绘图仪则需要一个小时才能生成(糟糕的)代码所产生的(糟糕的)图表。

不幸的是,我的尝试以失败、崩溃和沉入沼泽而告终。我隐约记得我因此获得了一片橙子和一张参与奖绶带。感谢您没有让我挂科,Dutta教授。

但十年后,借助IDL,在为IDL 5.0制作演示程序的竞赛中,我重新尝试了这一壮举。

结果在视觉上更加令人满意,尽管在物理上可能更不真实。

我大致原封不动地保留了下面的代码。这是一个主应用程序。注意里面的 DEVICE, DECOMPOSED=0 和圆括号而非方括号——这是100%的原版代码,我指的不是面向对象图形。

本质上,两个质点代表星系中心,1000个无质量测试点(“恒星”)被赋予围绕这些中心的初始圆形轨道。然后,两个星系中心在它们的质心系中运动,具有一些旨在产生视觉吸引人(尽管在物理上可能站不住脚)的结果的初始条件。

我基于这个主题写了很多变体,根据相对于质心的速度为恒星着色,添加了其他“星系”质量等等。如果你对此感兴趣,可以尝试改变相对质量和速度等初始参数。


; 初始化部分

G = 4.4999e-12 ; 秒差距^3 年^-2 太阳质量^-1

epsilon = 1.e5 ; 年
snapshot = 16.e6 ; 年
nsnapshots = 16
maxradius = 15d3 ; 秒差距
initialsep = 2.*maxradius
Ngalaxies = 2
GalaxyColors = [150, 200]
Nsuns = 1000

vx = dblarr(Ngalaxies*(Nsuns + 1)) & vy = vx & vz = vx & x = vx & y = vx
z = vx & m = vx & rdist=  vx & thetadist = vx & ax = vx & ay = vx & az = vx

m(0) = 10.d9 ; 太阳质量
x(0) = initialsep/2.*cos(!pi/4.)
y(0) = initialsep/2.*sin(!pi/4.)
m(1) = 9.d9 ; 太阳质量
x(1) = -x(0)
y(1) = -y(0)

speed = 2*sqrt(G*m(1)/initialsep)
vx(0) = -speed*sin(!pi/4.)/2.
vy(0) = speed*cos(!pi/4.)/2.
vx(1) = -vx(0)*sqrt(m(0)/m(1))/3.
vy(1) = -vy(0)*sqrt(m(0)/m(1))/3.

; 执行部分

device, decomposed = 0
iseed = 138987

for i = Ngalaxies, Ngalaxies*(Nsuns + 1) - 1 do begin
   rdist(i) = randomu(iseed) * maxradius
   thetadist(i) = randomu(iseed)*2*!pi
   m(i) = 1.
endfor

for j = 0, ngalaxies - 1 do begin
   for i = ngalaxies + j*nsuns, ngalaxies + (j + 1)*nsuns - 1 do begin
      x(i) = rdist(i)*cos(thetadist(i)) + x(j)
      y(i) = rdist(i)*sin(thetadist(i)) + y(j)
      z(i) = 0.
      speed = sqrt(G*m(j)/max([Abs(rdist(i)),1.e-30]))
      vx(i) = -speed*sin(thetadist(i)) + vx(j)
      vy(i) = speed*cos(thetadist(i)) + vy(j)
      vz(i) = 0.
   endfor
endfor

loadct,15
!ignore = -1
!x.style = 2
!y.style = 2
window, 1, xsize=700, ysize=700, xpos = 0, ypos = 0
wset, 1

for t = -epsilon, snapshot*(nsnapshots - 1), epsilon do begin
   ax(*) = 0 & ay = ax & az = ax
   for j = 0, NGalaxies - 1 do begin
      r = sqrt((x - x(j))^2 + (y - y(j))^2 + (z - z(j))^2)
      r3 = r^3 > 1.e-20
      Gprod = -G*m(j)/r3
      ax = Gprod*(x-x(j)) + ax
      ay = Gprod*(y-y(j)) + ay
      az = Gprod*(z-z(j)) + az
   endfor
   vx = vx + epsilon*ax
   vy = vy + epsilon*ay
   vz = vz + epsilon*az
   x = x + epsilon*vx
   y = y + epsilon*vy
   z = z + epsilon*vz

   if (t eq -epsilon) then begin
      rs = 1.5*initialsep
      plot, [rs, -rs], [rs, -rs], color = 0
      closedcircles,sym=1
      for i = 0, NGalaxies - 1 Do Begin
         oplot,[x(i),x(i)],[y(i),y(i)],color=galaxycolors(i)
      endfor
      !psym = 3
      for i = 0, NGalaxies - 1 Do Begin
         indices = indgen(nsuns) + (i*nsuns) + Ngalaxies
         oplot, x(indices), y(indices), color=galaxycolors(i)
      endfor
      oldx = x
      oldy = y
   endif else begin
      ;
      ; 擦除前一帧
      ;
      closedcircles,sym=1
      oplot,oldx(0:NGalaxies-1),oldy(0:NGalaxies-1), color = 0
      !psym = 3
      oplot, oldx, oldy, color = 0
      ;
      ; 绘制星系中心
      ;
      closedcircles,sym=1
      for i = 0, NGalaxies - 1 Do Begin
         oplot,[x(i),x(i)],[y(i),y(i)],color=galaxycolors(i)
      endfor
      ;
      ; 绘制恒星
      ;
      !psym = 3
      for i = 0, NGalaxies - 1 Do Begin
         indices = indgen(nsuns) + (i*nsuns) + Ngalaxies
         oplot, x(indices), y(indices), color=galaxycolors(i)
      endfor
      ;
      ; 保存坐标
      ;
      oldx = x
      oldy = y
      empty
   endelse
endfor
end

你还需要以下辅助程序。


Pro ClosedCircles, Symbol_Radius = Symbol_Radius, Color = Color

On_Error, 2

Ang = (360./47.*Findgen(48))/!RaDeg
X = Cos(Ang)
Y = Sin(Ang)

If (N_Elements(Symbol_Radius) ne 0) then Begin
    X = X * Symbol_Radius
    Y = Y * Symbol_Radius
EndIf

If (N_Elements(Color) eq 0) then Begin
    UserSym, X, Y, /Fill
EndIf Else Begin
    UserSym, X, Y, /Fill, Color = Color
EndElse

!P.PSym = 8

Return
End

User-Defined ENVITask That Masks Some Output Pixels Computer Based Training