{-# LANGUAGE TypeFamilies, FlexibleContexts #-}
{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE Safe #-}
module Physics.Learn.Curve
(
Curve(..)
, normalizeCurve
, concatCurves
, concatenateCurves
, reverseCurve
, evalCurve
, shiftCurve
, straightLine
, simpleLineIntegral
, dottedLineIntegral
, crossedLineIntegral
, compositeTrapezoidDottedLineIntegral
, compositeTrapezoidCrossedLineIntegral
, compositeSimpsonDottedLineIntegral
, compositeSimpsonCrossedLineIntegral
)
where
import Data.VectorSpace
( VectorSpace
, InnerSpace
, Scalar
)
import Physics.Learn.CarrotVec
( Vec
, (><)
, (<.>)
, sumV
, (^*)
, (^/)
, (^+^)
, (^-^)
, (*^)
, magnitude
, zeroV
, negateV
)
import Physics.Learn.Position
( Position
, Displacement
, displacement
, Field
, VectorField
, shiftPosition
)
data Curve = Curve { curveFunc :: Double -> Position
, startingCurveParam :: Double
, endingCurveParam :: Double
}
dottedLineIntegral
:: Int
-> VectorField
-> Curve
-> Double
dottedLineIntegral = compositeSimpsonDottedLineIntegral
crossedLineIntegral
:: Int
-> VectorField
-> Curve
-> Vec
crossedLineIntegral = compositeSimpsonCrossedLineIntegral
compositeTrapezoidDottedLineIntegral
:: Int
-> VectorField
-> Curve
-> Double
compositeTrapezoidDottedLineIntegral n vf (Curve f a b)
= sum $ zipWith (<.>) aveVecs dls
where
dt = (b - a) / fromIntegral n
pts = [f t | t <- [a,a+dt..b]]
vecs = [vf pt | pt <- pts]
aveVecs = zipWith average vecs (tail vecs)
dls = zipWith displacement pts (tail pts)
compositeTrapezoidCrossedLineIntegral
:: Int
-> VectorField
-> Curve
-> Vec
compositeTrapezoidCrossedLineIntegral n vf (Curve f a b)
= sumV $ zipWith (><) aveVecs dls
where
dt = (b - a) / fromIntegral n
pts = [f t | t <- [a,a+dt..b]]
vecs = [vf pt | pt <- pts]
aveVecs = zipWith average vecs (tail vecs)
dls = zipWith displacement pts (tail pts)
simpleLineIntegral
:: (InnerSpace v, Scalar v ~ Double)
=> Int
-> Field v
-> Curve
-> v
simpleLineIntegral n vf (Curve f a b)
= sumV $ zipWith (^*) aveVecs (map magnitude dls)
where
dt = (b - a) / fromIntegral n
pts = [f t | t <- [a,a+dt..b]]
vecs = [vf pt | pt <- pts]
aveVecs = zipWith average vecs (tail vecs)
dls = zipWith displacement pts (tail pts)
normalizeCurve :: Curve -> Curve
normalizeCurve (Curve f a b)
= Curve (f . scl) 0 1
where
scl t = a + (b - a) * t
concatCurves :: Curve
-> Curve
-> Curve
concatCurves c1 c2
= normalizeCurve $ Curve f 0 2
where
(Curve f1 _ _) = normalizeCurve c1
(Curve f2 _ _) = normalizeCurve c2
f t | t <= 1 = f1 t
| otherwise = f2 (t-1)
concatenateCurves :: [Curve] -> Curve
concatenateCurves [] = error "concatenateCurves: cannot concatenate empty list"
concatenateCurves cs = normalizeCurve $ Curve f 0 (fromIntegral n)
where
n = length cs
ncs = map normalizeCurve cs
f t = evalCurve (ncs !! m) (t - fromIntegral m)
where m = min (n-1) (floor t)
reverseCurve :: Curve -> Curve
reverseCurve (Curve f a b)
= Curve (f . rev) a b
where
rev t = a + b - t
evalCurve :: Curve
-> Double
-> Position
evalCurve (Curve f _ _) t = f t
shiftCurve :: Displacement
-> Curve
-> Curve
shiftCurve d (Curve f sl su)
= Curve (shiftPosition d . f) sl su
straightLine :: Position
-> Position
-> Curve
straightLine r1 r2 = Curve f 0 1
where
f t = shiftPosition (t *^ d) r1
d = displacement r1 r2
average :: (VectorSpace v, Scalar v ~ Double) => v -> v -> v
average v1 v2 = (v1 ^+^ v2) ^/ 2
dottedSimp :: (InnerSpace v, Fractional (Scalar v)) =>
v
-> v
-> v
-> v
-> v
-> Scalar v
dottedSimp f0 f1 f2 g10 g21
= ((g21 ^+^ g10) ^/ 6) <.> (f0 ^+^ 4 *^ f1 ^+^ f2)
+ ((g21 ^-^ g10) ^/ 3) <.> (f2 ^-^ f0)
compositeSimpsonDottedLineIntegral
:: Int
-> VectorField
-> Curve
-> Double
compositeSimpsonDottedLineIntegral n vf (Curve c a b)
= let nEven = 2 * div n 2
dt = (b - a) / fromIntegral nEven
ts = [a + fromIntegral m * dt | m <- [0..nEven]]
pairs = [(ct,vf ct) | t <- ts, let ct = c t]
combine [] = error "compositeSimpson: odd number of half-intervals"
combine [_] = zeroV
combine (_:_:[]) = error "compositeSimpson: odd number of half-intervals"
combine ((c0,f0):(c1,f1):(c2,f2):ps)
= dottedSimp f0 f1 f2 (displacement c0 c1) (displacement c1 c2)
^+^ combine ((c2,f2):ps)
in combine pairs
crossedSimp :: Vec
-> Vec
-> Vec
-> Vec
-> Vec
-> Vec
crossedSimp f0 f1 f2 g10 g21
= negateV $
((g21 ^+^ g10) ^/ 6) >< (f0 ^+^ 4 *^ f1 ^+^ f2)
^+^ ((g21 ^-^ g10) ^/ 3) >< (f2 ^-^ f0)
compositeSimpsonCrossedLineIntegral
:: Int
-> VectorField
-> Curve
-> Vec
compositeSimpsonCrossedLineIntegral n vf (Curve c a b)
= let nEven = 2 * div n 2
dt = (b - a) / fromIntegral nEven
ts = [a + fromIntegral m * dt | m <- [0..nEven]]
pairs = [(ct,vf ct) | t <- ts, let ct = c t]
combine [] = error "compositeSimpson: odd number of half-intervals"
combine [_] = zeroV
combine (_:_:[]) = error "compositeSimpson: odd number of half-intervals"
combine ((c0,f0):(c1,f1):(c2,f2):ps)
= crossedSimp f0 f1 f2 (displacement c0 c1) (displacement c1 c2)
^+^ combine ((c2,f2):ps)
in combine pairs