{-|
Module      : Physics
Description : Implementation of required physics for N-body problem

Implements a post-newtonian weak-field approximation gravitational acceleration
function and associated vector types required for three dimensional physics.

For more information on Post-Newtonian formulations used herein see [1],
[2] (Eq. 1) and references therein.

[1] /The IAU 2000 Resolutions for Astrometry, Celestial Mechanics, and Metrology in the Relativistic Framework: Explanatory Supplement/, /Soffel et al./, 2003. Astronomical Journal, 126:2687-2706.

[2] /Cometary Orbit Determination and Nongravitational Forces/, /Yeomans et al./

-}

module Physics
       (
         Vec(..)
       , Vec3(..)
       , Vec2(..)
       , pNGRPair
       , pNGRFull
       , CutParams(..)
       ) where

import PhysicsVectors
import PhysicsConstants
import AstroData

-- | Cutoff parameters for GR corrections, 'CutParams' @masscut distcut@
data CutParams a = CutParams a a

chkCutoff :: (Ord f, Floating f) => CutParams f -> OrbitBody f -> OrbitBody f -> Bool
chkCutoff (CutParams mc dc) source targ
  | mc <= bGM source && stDist <= dc = True
  | otherwise = False
  where
      stDist = dist (obPos source) (obPos targ)

-- | Computes the pair-wise gravitational acceleration between two bodies
pNGRPair :: (Ord f, Floating f) => OrbitBody f -> OrbitBody f -> CutParams f -> Vec3 f
pNGRPair source target grcut
  | bid source == bid target = fromScalar 0
  | not $ chkCutoff grcut source target = newton
  | otherwise =
      newton + ((dot vst vst/cAUsq) `scalarMult` newton) + (ms/cAUsq) `scalarMult` grcor'
  where
    rst = (obPos target) - (obPos source)
    ms = bGM source
    (r2, r3) = let r2' = normSq rst in (r2', r2' * sqrt r2')
    newton = (-ms/r3) `scalarMult` rst
    cAUsq = fromRational (cAU * cAU)
    vst = (obVel target) - (obVel source)
    grcor' = ((4*ms/(r2*r2)) `scalarMult` rst) + ((4*dot rst vst/r3) `scalarMult` vst)

pNGRFull
  :: (Ord f, Floating f, Traversable t)
  => t (OrbitBody f)
  -> OrbitBody f
  -> CutParams f
  -> Vec3 f
pNGRFull bodies targ grcut = foldl (\acc b' -> acc + pNGRPair b' targ grcut) 0 bodies