packages feed

dynobud-1.0.0.0: src/Dyno/DirectCollocation/Quadratures.hs

{-# OPTIONS_GHC -Wall #-}
{-# Language ScopedTypeVariables #-}
{-# Language FlexibleContexts #-}
{-# Language DeriveGeneric #-}

module Dyno.DirectCollocation.Quadratures
       ( QuadratureRoots(..)
       , mkTaus
       , interpolate
       , timesFromTaus
       , collocationTimes
       ) where

import GHC.Generics ( Generic )
import Data.Proxy ( Proxy(..) )
import qualified Data.Vector as V
import qualified Data.Foldable as F
import Data.Serialize ( Serialize(..) )
import Linear.V

import JacobiRoots ( shiftedLegendreRoots ) --, shiftedRadauRoots )

import Dyno.View
import Dyno.TypeVecs ( Vec )
import qualified Dyno.TypeVecs as TV
import Dyno.LagrangePolynomials ( lagrangeXis )

data QuadratureRoots = Legendre | Radau deriving (Show, Eq, Ord, Enum, Generic)
instance Serialize QuadratureRoots

mkTaus ::
  forall deg a
  . (Dim deg, Fractional a)
  => QuadratureRoots -> Vec deg a
mkTaus quadratureRoots = case taus of
  Just taus' -> TV.mkVec $ V.map (fromRational . toRational) taus'
  Nothing -> error "makeTaus: too high degree"
  where
    deg = reflectDim (Proxy :: Proxy deg)
    taus = case quadratureRoots of
      Legendre -> shiftedLegendreRoots deg
      Radau -> error "radau not yet supported" -- shiftedRadauRoots (deg-1) ++ [1.0]


dot :: forall x deg a b. (Fractional (J x a), Real b) => Vec deg b -> Vec deg (J x a) -> J x a
dot cks xs = F.sum $ TV.unSeq elemwise
  where
    elemwise :: Vec deg (J x a)
    elemwise = TV.tvzipWith smul cks xs

    smul :: b -> J x a -> J x a
    smul x y = realToFrac x * y


interpolate :: (Dim deg, Real b, Fractional b, Fractional (J x a), View x) =>
               Vec deg b -> J x a -> Vec deg (J x a) -> J x a
interpolate taus x0 xs = dot (TV.mkVec' xis) (x0 TV.<| xs)
  where
    xis = map (lagrangeXis (0 : F.toList taus) 1) [0..deg]
    deg = TV.tvlength taus


timesFromTaus ::
  forall n deg a
  . (Num a, Dim n, Dim deg)
  => a -> Vec deg a -> a -> Vec n (a, Vec deg a)
timesFromTaus t0 taus dt = times
  where
    n = reflectDim (Proxy :: Proxy n)

    -- initial time at each collocation stage
    t0s :: Vec n a
    t0s = TV.mkVec' $ take n [t0 + (dt * fromIntegral k) | k <- [(0::Int)..]]

    -- times at each collocation point
    times :: Vec n (a, Vec deg a)
    times = fmap (\t0' -> (t0', fmap (\tau -> t0' + tau * dt) taus)) t0s

collocationTimes ::
  (Dim n, Dim deg, Fractional a) => a -> QuadratureRoots -> a -> Vec n (a, Vec deg a)
collocationTimes t0 qr dt = timesFromTaus t0 (mkTaus qr) dt