3

我正在使用Haskell進行粒子模擬程序。對於其中一個函數,我試圖根據所有周圍粒子的質量和速度來確定模擬中所有粒子的新速度。Haskell粒子模擬 - 計算粒子速度

功能是這個形式:

accelerate :: Float -> [Particle] -> [Particle] 

粒子是包含質量,位置矢量和的速度矢量數據類型,「浮動」參數表示在各個時間步的增量時間模擬

我想對可能的函數提供一些建議,我可以用它來遍歷列表,同時計算每個粒子相對於列表中其他粒子的速度。

一種可能的方法,我能想到的:

  1. 假設有另一個功能「velocityCalculator」的定義如下:

    velocityCalculator :: Particle -> Particle -> (Float,Float) 
    

這需要兩個粒子並返回更新第一個粒子的速度矢量。

  1. apply foldl;使用上述函數作爲二進制運算符,顆粒和顆粒作爲參數的列表,即

    foldl velocityCalculator particle particleList 
    
  2. 迭代通過粒子的列表中,將與foldl到每個元件和構建包含與顆粒的新列表更新的速度

我不確定這是否是最有效的方法,所以任何建議和改進都非常感謝。

請注意 - >正如我所說我只是在尋找建議而不是答案!

謝謝!

+0

你想應用速度verlet算法或類似的東西嗎?我的意思是,你是否願意用一些分析或數字勢能來整合牛頓的運動方程? – felipez

+0

沒有什麼特別的,我只是在haskell中尋找可能的更高階的函數,它可以在列表中應用velocityCalculator函數更快地完成工作 – dfj328

回答

3

看起來像你很漂亮的使用foldl。例如

通過粒子的列表中
  • 迭代,施加foldl到每個元件和構建包含與更新速度
  • 並不真正使顆粒將新列表感。根據一些二進制彙總函數,您可以將foldl應用於列表以將其降至「彙總值」。將它應用於單個粒子沒有意義。

    我回答了這個問題,假設你在編寫程序時遇到了麻煩 - 通常最好在擔心效率之前這樣做。如果我錯了,請告訴我。

    我不確定你想用什麼規則來更新速度,但我認爲它是某種形式的成對力仿真,例如重力或電磁。如果是這樣,這裏有一些提示可以指導你解決問題。

    type Vector = (Float, Float) 
    
    -- Finds the force exerted on one particle by the other. 
    -- Your code will be simplified if this returns (0,0) when the two 
    -- particles are the same. 
    findForce :: Particle -> Particle -> Vector 
    
    -- Find the sum of all forces exerted on the particle 
    -- by every particle in the list. 
    totalForce :: [Particle] -> Particle -> Vector 
    
    -- Takes a force and a particle to update, returns the same particle with 
    -- updated velocity. 
    updateVelocity :: Vector -> Particle -> Particle 
    
    -- Calculate mutual forces and update all particles' velocities 
    updateParticles :: [Particle] -> [Particle] 
    

    這些功能中的每一個都會很短,一兩行。如果您需要進一步提示了其高階函數的使用,注意你正在嘗試寫函數的類型,並注意

    map :: (a -> b) -> [a] -> [b]   -- takes a list, returns a list 
    filter :: (a -> Bool) -> [a] -> [a]  -- takes a list, returns a list 
    foldl :: (a -> b -> a) -> a -> [b] -> a -- takes a list, returns something else 
    foldr :: (a -> b -> b) -> b -> [a] -> b -- takes a list, returns something else 
    
    2

    你可以通過記憶化一個2的倍數達到了加速,如果你給每一個Particle ID particle_id :: Int,然後定義:

    forceOf a b | particle_id a > particle_id b = -(forceOf b a) 
          | otherwise = (pos a - pos b) *:. charge a * charge b/norm (pos a - pos b)^3 
    

    其中(*:.) :: Vector -> Double -> Vector是矢量標量乘法所以上面是1/r^2力定律。注意,在這裏我們記憶pos a - pos b,然後我們也記憶forceOf a b用作forceOf b a

    然後你想使用dvs = [dt * sum (map (forceOf a) particles)/mass a | a <- particles]來獲得速度的更改列表,然後zipWith (+) (map velocity particles) dvs

    的一個問題是,這種做法不符合數值不確定做的這麼好:家居時間$ T + 1個$是基於在$ t $時刻是真實的事情。您可以通過求解矩陣方程來開始解決這個問題;代替v + = V + DT * 中號 V(其中V = V(t)和V + = V(T + 1)),可以編寫v + = V + DT * 中號 v +,讓你有v + =( - DT * 中號-1信息v往往可以更數值穩定。將兩種解決方案50/50混合可能更好。 v + = v + dt * M(v + v +)/ 2.這裏有很多選擇。