dynobud-1.9.0.0: examples/Spring.hs
{-# OPTIONS_GHC -Wall #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DataKinds #-}
module Main ( SpringX(..), SpringU(..), main ) where
import GHC.Generics ( Generic, Generic1 )
import Data.Vector ( Vector )
import Accessors ( Lookup )
import Dyno.View.View ( J, jfill, catJV )
import Dyno.Nlp ( Bounds )
import Dyno.Ocp
import Dyno.Vectorize ( Vectorize, None(..), fill )
import Dyno.Solvers ( Solver(..), Opt(..), ipoptSolver )
import Dyno.NlpUtils ( solveNlp )
import Dyno.DirectCollocation.Formulate
( CollProblem(..), DirCollOptions(..), MapStrategy(..), makeCollProblem )
import Dyno.DirectCollocation.Types ( CollTraj' )
import Dyno.DirectCollocation.Dynamic ( toMeta )
import Dyno.DirectCollocation.Quadratures ( QuadratureRoots(..) )
import Dynoplot.Callback ( withCallback )
springOcp :: OcpPhase' SpringOcp
springOcp =
OcpPhase
{ ocpMayer = mayer
, ocpLagrange = lagrange
, ocpQuadratures = \_ _ _ _ _ _ _ _ -> None
, ocpQuadratureOutputs = \_ _ _ _ _ _ _ _ -> None
, ocpDae = dae
, ocpBc = bc
, ocpPathC = pathC
, ocpPlotOutputs = \_ _ _ _ _ _ _ _ _ _ _ -> None
, ocpObjScale = Nothing
, ocpTScale = Nothing
, ocpXScale = Nothing
, ocpZScale = Nothing
, ocpUScale = Nothing
, ocpPScale = Nothing
, ocpResidualScale = Nothing
, ocpBcScale = Nothing
, ocpPathCScale = Nothing
}
springOcpInputs :: OcpPhaseInputs' SpringOcp
springOcpInputs =
OcpPhaseInputs
{ ocpBcBnds = bcBnds
, ocpPathCBnds = pathCBnds
, ocpXbnd = fill (Nothing, Nothing)
, ocpZbnd = fill (Nothing, Nothing)
, ocpUbnd = fill (Nothing, Nothing)
, ocpPbnd = fill (Nothing, Nothing)
, ocpTbnd = (Just 4, Just 4)
, ocpFixedP = None
}
data SpringOcp
type instance X SpringOcp = SpringX
type instance O SpringOcp = SpringO
type instance R SpringOcp = SpringX
type instance U SpringOcp = SpringU
type instance C SpringOcp = SpringBc
type instance H SpringOcp = SpringPathC
type instance P SpringOcp = None
type instance Z SpringOcp = None
type instance Q SpringOcp = None
type instance QO SpringOcp = None
type instance FP SpringOcp = None
type instance PO SpringOcp = None
data SpringX a =
SpringX
{ xPos :: a
, xVel :: a
} deriving (Functor, Generic, Generic1)
data SpringU a =
SpringU
{ uMotor :: a
} deriving (Functor, Generic, Generic1)
data SpringO a =
SpringO
{ oForce :: a
, oObj :: a
} deriving (Functor, Generic, Generic1)
data SpringBc a =
SpringBc
{ bcX0 :: SpringX a
, bcXF :: SpringX a
} deriving (Functor, Generic, Generic1)
data SpringPathC a = SpringPathC a deriving (Functor, Generic, Generic1)
instance Vectorize SpringX
instance Vectorize SpringU
instance Vectorize SpringO
instance Vectorize SpringBc
instance Vectorize SpringPathC
instance Lookup a => Lookup (SpringX a)
instance Lookup a => Lookup (SpringU a)
instance Lookup a => Lookup (SpringO a)
instance Lookup a => Lookup (SpringBc a)
instance Lookup a => Lookup (SpringPathC a)
dae :: Floating a
=> SpringX a -> SpringX a -> None a -> SpringU a -> None a -> None a -> a
-> (SpringX a, SpringO a)
dae (SpringX p' v') (SpringX p v) _ (SpringU u) _ _ t =
(residual, outputs)
where
residual = SpringX (p' - v) (v' - force)
outputs = SpringO { oForce = force
, oObj = obj
}
k = 4
b = 0.3
force = u - k * p - b * v + 0.1 * sin t
obj = p**2 + v**2 + u**2
bc :: SpringX a -> SpringX a -> None a -> None a -> None a -> a -> SpringBc a
bc x0 xf _ _ _ _ = SpringBc x0 xf
bcBnds :: SpringBc Bounds
bcBnds =
SpringBc
{ bcX0 = SpringX (Just 0, Just 0) (Just 0, Just 0)
, bcXF = SpringX (Just 1, Just 1) (Just 0, Just 0)
}
mayer :: Floating a => a -> SpringX a -> SpringX a -> None a -> None a -> None a -> a
mayer endTime _ (SpringX pf vf) _ _ _ = (pf**2 + vf**2 + endTime/1000)
pathC :: Floating a => SpringX a -> None a -> SpringU a -> None a -> None a -> SpringO a -> a -> SpringPathC a
pathC (SpringX _ v) _ (SpringU u) _ _ _ time =
SpringPathC (v**2 + u**2 - time/100)
pathCBnds :: SpringPathC Bounds
pathCBnds = SpringPathC (Nothing, Just 4)
lagrange :: Fractional a => SpringX a -> None a -> SpringU a -> None a -> None a -> SpringO a -> a -> a -> a
lagrange _ _ _ _ _ (SpringO force obj) _ _ = obj + force*force*1e-4
solver :: Solver
solver = ipoptSolver { options = [("expand", Opt True)] }
guess :: J (CollTraj' SpringOcp NCollStages CollDeg) (Vector Double)
guess = jfill 1
type NCollStages = 100
type CollDeg = 3
dirCollOpts :: DirCollOptions
dirCollOpts =
DirCollOptions
{ mapStrategy = Unrolled
, collocationRoots = Legendre
}
main :: IO ()
main =
withCallback $ \send -> do
cp <- makeCollProblem dirCollOpts springOcp springOcpInputs guess
let nlp = cpNlp cp
meta = toMeta (cpMetaProxy cp)
cb' traj _ = do
plotPoints <- cpPlotPoints cp traj (catJV None)
send (plotPoints, meta)
_ <- solveNlp solver nlp (Just cb')
return ()