All compile errors fixed, but now there's a weird NaN. The wonders never cease

This commit is contained in:
2023-01-30 21:40:58 +01:00
parent e45fab1389
commit cf300f3f88
7 changed files with 179 additions and 37 deletions

View File

@@ -1,15 +1,20 @@
module Main where module Main where
import Control.Lens import Control.Lens
import Criterion.Main import Control.Lens.Unsound (adjoin)
import Control.Monad.Writer
-- import Criterion.Main
import Data.Default
import Data.Either import Data.Either
import Petzval.Optics import Petzval.Optics
import Petzval.Optics.RTM import Petzval.Optics.RTM
import Petzval.System import Petzval.System
import Petzval.Merit
import Petzval.Trace import Petzval.Trace
import Petzval.Calculations import Petzval.Calculations
import Petzval.Optimization import Petzval.Optimization
import Petzval.Types import Petzval.Types
import System.Environment (getArgs)
import Linear import Linear
import Numeric.AD.Mode (Scalar, Mode) import Numeric.AD.Mode (Scalar, Mode)
import qualified Numeric.LinearAlgebra as L import qualified Numeric.LinearAlgebra as L
@@ -41,13 +46,13 @@ system2 =
, Surface{_material=s_sk16, _outsideRadius = 11, _roc=656.66349, _thickness = 4.5} , Surface{_material=s_sk16, _outsideRadius = 11, _roc=656.66349, _thickness = 4.5}
, Surface{_material = air, _outsideRadius = 11, _roc = -33.50754, _thickness = 86.48643} , Surface{_material = air, _outsideRadius = 11, _roc = -33.50754, _thickness = 86.48643}
] ]
where s_sk16 = ConstMat 1.620408 where s_sk16 = constMat 1.620408 :: SellemeierMat
s_f4 = ConstMat 1.616589 s_f4 = constMat 1.616589
merit :: (Material mat, Calcuable a) => [Element mat a] -> a merit :: (Material mat, Calcuable a) => [Element mat a] -> a
-- merit :: (Material mat) => [Element mat Double] -> Double -- merit :: (Material mat) => [Element mat Double] -> Double
merit system = result merit system = result
where baked = bake 0.587618 system where baked = bake 0.5875618 system
ep = entrancePupil baked ep = entrancePupil baked
result = sum result = sum
. map (^2) . map (^2)
@@ -63,6 +68,17 @@ merit system = result
type Id a = a -> a type Id a = a -> a
doOptimize steps = runWriterT $ optimizeDLS cfg vars merit system1
where merit = mkMerit [ DynMerit $ TW 50 100 $ BFL Nothing
, DynMerit $ TW 0 1 $ SpotSize Nothing
]
vars :: VariableSet
vars = (ix 1 . roc) `adjoin` (ix 2 . roc)
vars2 = undefined -- foldl1 adjoin
-- [ ix 1.roc , ix 2.roc]
cfg = def{maxSteps = steps}
main :: IO () main :: IO ()
main = main =
@@ -70,10 +86,14 @@ main =
ep = (entrancePupil baked){position=20.4747094540} ep = (entrancePupil baked){position=20.4747094540}
fa = 20 fa = 20
in do in do
[arg] <- getArgs
let steps = read arg
print $ L.norm_2 (L.fromList [3.0 , 4.0] :: L.Vector Double) print $ L.norm_2 (L.fromList [3.0 , 4.0] :: L.Vector Double)
doOptimize steps >>= print
putStrLn $ show ep putStrLn $ show ep
putStrLn $ show $ rearFocalLength $ lensRTM baked putStrLn $ show $ rearFocalLength $ lensRTM baked
putStrLn $ show $ mconcat (seidel ep fa baked :: [Seidel Double]) putStrLn $ show $ mconcat (seidel ep fa baked :: [Seidel Double])
{- defaultMain [ {- defaultMain [
bgroup "merit" [ bench "system1" $ nf merit (system1 :: [Element SellemeierMat Double]) bgroup "merit" [ bench "system1" $ nf merit (system1 :: [Element SellemeierMat Double])
, bench "system2" $ nf merit (system2 :: [Element ConstMat Double]) , bench "system2" $ nf merit (system2 :: [Element ConstMat Double])

View File

@@ -15,7 +15,8 @@ rmsSize' :: Floating a => V2 a -> [V2 a] -> a
rmsSize' centroid = sqrt . uncurry (/) . foldl1' (bimap2 (+) (+)) . map (quadrance . (^-^ centroid) &&& (const 1)) rmsSize' centroid = sqrt . uncurry (/) . foldl1' (bimap2 (+) (+)) . map (quadrance . (^-^ centroid) &&& (const 1))
rmsSize :: Floating a => [V2 a] -> a rmsSize :: Floating a => [V2 a] -> a
rmsSize = centroid >>= rmsSize' rmsSize [] = 1/0
rmsSize points = rmsSize' (centroid points) points
centroid :: Fractional a => [V2 a] -> V2 a centroid :: Fractional a => [V2 a] -> V2 a
centroid = uncurry (^/) . foldl1' (bimap2 (^+^) (+)) . map (flip (,) 1) centroid = uncurry (^/) . foldl1' (bimap2 (^+^) (+)) . map (flip (,) 1)

View File

@@ -1,33 +1,123 @@
module Petzval.Merit where {- LANGUAGE ImpredicativeTypes #-}
module Petzval.Merit (BFL(..), SpotSize(..), DynMerit(..), TW(..), Merit(..), MeritFunction, evalMerit, mkMerit) where
import Petzval.Calculations import Petzval.Calculations
import Petzval.Types import Petzval.Types
import Petzval.Trace import Petzval.Trace
import Petzval.Optics (Element, BakedIOR) import Petzval.Optics (Element, BakedIOR, SellemeierMat, bake)
import Petzval.System import Petzval.System
import Control.Lens import Control.Lens
import Data.Either import Data.Either
import Data.Default
import Petzval.Optics.RTM
import Linear import Linear
import Data.Maybe
import Numeric.AD.Mode (auto)
import qualified Data.Map as Map import qualified Data.Map as Map
type MeritPart a = [Element BakedIOR a] -> a type MeritPart a = TracedSystem a -> a
data Calcuable a => TracedSystem a =
TracedSystem { system :: [Element BakedIOR a] data TraceConditions = TraceConditions { fieldAngle :: Double
, field_angles :: [Double] , wavelength :: Double
, wavelengths :: [Double]
, tracePoints :: [(Ray a, HitRecord a)]
} }
deriving (Show)
data TracedSystem a =
TracedSystem { _innerSystem :: [Element SellemeierMat a]
, _fieldAngles :: [Double]
, _wavelengths :: [Double]
--, _tracePoints :: Map.Map TraceConditions [(Ray a, HitRecord a)]
}
makeLenses ''TracedSystem
defWavelength :: (TracedSystem a) -> Double
defWavelength = fromMaybe 0.5875618 . listToMaybe . _wavelengths
defFA :: TracedSystem a -> Double
defFA = fromMaybe 0 . listToMaybe . _fieldAngles
defTraceConditions :: TracedSystem a -> TraceConditions
defTraceConditions = TraceConditions <$> defFA <*> defWavelength
systemAtWavelength :: Double -> TracedSystem a -> [Element BakedIOR a]
systemAtWavelength λ = bake λ . _innerSystem
class Merit m where
calc :: Calcuable a => m -> TracedSystem a -> a
data SpotSize = SpotSize (Maybe TraceConditions)
deriving (Show)
spotSize :: Calcuable a => a -> MeritPart a instance Merit SpotSize where
spotSize fa system = rmsSize calc (SpotSize Nothing) sys = calc (SpotSize (Just $ defTraceConditions sys)) sys
calc (SpotSize (Just a)) sys = spotSize' a sys
data BFL = BFL (Maybe Double)
deriving (Show)
instance Merit BFL where
calc (BFL Nothing) = bfl
calc (BFL (Just wl)) = bfl' wl
spotSize' :: Calcuable a => TraceConditions -> MeritPart a
spotSize' conditions ts = rmsSize
. toListOf (each._pos._xy) . toListOf (each._pos._xy)
. rights . rights
. map fst . map fst
. map (raytrace system) . map (raytrace system)
. map (createRay Nothing ep fa) . map (createRay Nothing ep fa)
$ hexapolarPattern 10 $ hexapolarPattern 10
where ep = entrancePupil system where
system = systemAtWavelength (wavelength conditions) ts
fa = auto $ fieldAngle conditions
ep = entrancePupil system
spotSize :: Calcuable a => MeritPart a
spotSize = defTraceConditions >>= spotSize'
-- | Compute the back focal length
bfl :: Calcuable a => MeritPart a
-- | Compute the back focal length at a specific wavelength
bfl' :: (Calcuable a)
=> Double -- ^ Wavelength
-> MeritPart a -- ^ Merit function
bfl' wavelength = rearFocalLength . systemRTM . systemAtWavelength wavelength
bfl = defWavelength >>= bfl'
data TW m = TW Double Double m
deriving (Show)
instance Merit m => Merit (TW m) where
calc (TW target weight merit) system = auto weight * (calc merit system - auto target)
component :: Calcuable a => Double -> Double -> MeritPart a -> MeritPart a
component target weight part system = let value = part system
in (value - auto target) * auto weight
data MeritFunction = MeritFunction { components :: [DynMerit]
, fnFieldAngles :: [Double]
, fnWavelengths :: [Double]
}
mkMerit :: [DynMerit] -> MeritFunction
mkMerit parts = MeritFunction {
components = parts
, fnFieldAngles = []
, fnWavelengths = []
}
data DynMerit = forall m. (Show m, Merit m) => DynMerit m
instance Merit DynMerit where
calc (DynMerit m) = calc m
evalMerit :: Calcuable a => MeritFunction -> [Element SellemeierMat a] -> [a]
evalMerit fn system =
let ts = TracedSystem {
_innerSystem=system
, _fieldAngles=fnFieldAngles fn
, _wavelengths = fnWavelengths fn
}
in fmap (flip calc ts) $ components fn
-- fmap ($ts) $ components fn

View File

@@ -90,9 +90,9 @@ specialize :: (Material mat) => Double -> [Element mat a] -> [Element ConstMat a
specialize wavelength = (each.material) %~ (ConstMat . iorAtWavelength wavelength) specialize wavelength = (each.material) %~ (ConstMat . iorAtWavelength wavelength)
-- | Annotate each material with the incoming index of refraction -- | Annotate each material with the incoming index of refraction
bake :: (Material mat) => Double -> [Element mat a] -> [Element BakedIOR a] bake :: (Material mat) => Double -> [Element mat a] -> [Element BakedIOR a]
bake wavelength mat = bake wavelength system =
snd $ snd $
mapAccumLOf (each.material) (\n1 (ConstMat n2) -> (n2, BakedIOR n1 n2)) 1 $ mapAccumLOf (each.material) (\n1 (ConstMat n2) -> (n2, BakedIOR n1 n2)) 1 $
specialize wavelength mat specialize wavelength system

View File

@@ -2,6 +2,7 @@
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE NoMonomorphismRestriction #-} {-# LANGUAGE NoMonomorphismRestriction #-}
{- LANGUAGE ImpredicativeTypes #-}
module Petzval.Optimization where module Petzval.Optimization where
import Linear import Linear
@@ -13,11 +14,15 @@ import Control.Lens
import Control.Lens.Unsound (adjoin) import Control.Lens.Unsound (adjoin)
import Numeric.AD.Mode (auto) import Numeric.AD.Mode (auto)
import Numeric.AD.Mode.Reverse.Double import Numeric.AD.Mode.Reverse.Double
import Petzval.Merit
import Petzval.Optics import Petzval.Optics
import Petzval.Types import Petzval.Types
import Control.Monad.Writer.Class import Control.Monad.Writer.Class
import Data.Default
import Numeric.LinearAlgebra hiding (Element, dot) import Debug.Trace
import Numeric.LinearAlgebra hiding (Element, dot, (??))
import qualified Numeric.LinearAlgebra as L import qualified Numeric.LinearAlgebra as L
@@ -53,23 +58,40 @@ data DLSCfg = DLSCfg { eps1 :: Double -- ^ Cutoff for the derivative of the metr
, eps2 :: Double -- ^ Cutoff for no longer making progress , eps2 :: Double -- ^ Cutoff for no longer making progress
, maxSteps :: Integer -- ^ Maximum number of steps to iterate , maxSteps :: Integer -- ^ Maximum number of steps to iterate
} }
instance Default DLSCfg where
def = DLSCfg 1e-8 1e-4 1000
makeLenses ''DLSState makeLenses ''DLSState
{-
evalMeritJ :: MeritFunction -> VariableSet -> [Element SellemeierMat Double] -> [(Double, [Double])]
evalMeritJ fn vars system =
let ts sys = TracedSystem {
_system=sys
, _fieldAngles=fieldAngles fn
, _wavelengths = wavelengths fn
}
evalAt pt = fmap ($lts) $ components fn
where lts = ts $ setVars vars (system & each.liftFp %~ auto) pt
in unzip . jacobian' . evalAt $ extractVars vars system
-}
optimizeDLS :: (MonadWriter [[Double]] m -- ^ This yields a list of intermediate values of the merit function optimizeDLS :: (MonadWriter [[Double]] m -- ^ This yields a list of intermediate values of the merit function
) , MonadIO m)
=> DLSCfg => DLSCfg
-> VariableSet -- ^ The set of independent variables -> VariableSet -- ^ The set of independent variables
-> (forall a. Calcuable a => [Element mat a] -> [a]) -- ^ merit function -> MeritFunction -- ^ merit function
-> [Element mat Double] -- ^ The system -> [Element SellemeierMat Double] -- ^ The system
-> m [Element mat Double] -> m [Element SellemeierMat Double]
optimizeDLS cfg vars merit system = fmap (setVars vars system . toList) $ evalStateT doOptimize initialState optimizeDLS cfg vars merit system = fmap (setVars vars system . toList) $ evalStateT doOptimize initialState
where where
initialState = let pt = fromList $ extractVars vars system initialState = let pt = fromList $ extractVars vars system
(y,j) = jacobianAt pt (y,j) = traceShowId $ jacobianAt pt
a :: Matrix Double = tr j L.<> j a :: Matrix Double = tr j L.<> j
damping :: Double = 1e-3 * (maximum . toList . takeDiag) a damping :: Double = 1e-3 * (maximum . toList . takeDiag) a
lastSum = sum . map (^2) . merit $ system lastSum = sum . map (^2) . evalMerit merit $ system
in DLSState { _damping=damping in DLSState { _damping=damping
, _lastSum=lastSum , _lastSum=lastSum
, _curPt=pt , _curPt=pt
@@ -82,13 +104,14 @@ optimizeDLS cfg vars merit system = fmap (setVars vars system . toList) $ evalSt
-- optimizeStep :: m Double, where the return value is the change in merit -- optimizeStep :: m Double, where the return value is the change in merit
optimizeStep = do optimizeStep = do
mu <- use damping mu <- use damping
liftIO . print $ "Damping: " ++ show mu
lastPt <- use curPt lastPt <- use curPt
let (y, a) = jacobianAt lastPt let (y, a) = jacobianAt lastPt
let g = tr a #> y let g = tr a #> y
let dPt :: Vector Double = -(inv $ tr a L.<> a + (scalar mu * ident (cols a)) ) #> g let dPt :: Vector Double = -(inv $ tr a L.<> a + (scalar mu * ident (cols a)) ) #> g
let newPt = lastPt + dPt let newPt = lastPt + dPt
let oldMerit = sumSq y let oldMerit = sumSq y
let newMerit = sumSq . fromList . merit . setVars vars system . toList $ newPt let newMerit = sumSq . fromList . evalMerit merit . setVars vars system . toList $ newPt
let dL = (dPt `L.dot` (scalar mu * dPt - g)) / 2 let dL = (dPt `L.dot` (scalar mu * dPt - g)) / 2
let gain = (oldMerit - newMerit) / dL let gain = (oldMerit - newMerit) / dL
if gain > 0 if gain > 0
@@ -98,14 +121,17 @@ optimizeDLS cfg vars merit system = fmap (setVars vars system . toList) $ evalSt
found ||= (norm_2 g <= eps1 cfg || norm_2 dPt <= eps2 cfg * (norm_2 lastPt + eps2 cfg)) found ||= (norm_2 g <= eps1 cfg || norm_2 dPt <= eps2 cfg * (norm_2 lastPt + eps2 cfg))
curPt .= newPt curPt .= newPt
else do scale <- use dampScale else do scale <- use dampScale
d <- use damping
dampScale *= 2 dampScale *= 2
liftIO $ print ("Rescaling", scale, d)
damping *= scale damping *= scale
tell [toList y] tell [toList y]
return $ newMerit - oldMerit return $ newMerit - oldMerit
jacobianAt :: Vector Double -> (Vector Double, Matrix Double) jacobianAt :: Vector Double -> (Vector Double, Matrix Double)
jacobianAt pt = let (y,a) = unzip . jacobian' (merit . setVars vars (system & each.liftFp %~ auto)) $ toList pt jacobianAt pt = let eval pt = undefined
(y,a) = unzip . jacobian' (\adpt -> evalMerit merit $ setVars vars (system & each.liftFp %~ auto) adpt) $ toList pt
in (fromList y, fromLists a) in (fromList y, fromLists a)
sumSq :: Vector Double -> Double sumSq :: Vector Double -> Double

View File

@@ -1,4 +1,4 @@
{-# LANGUAGE FlexibleInstances, UndecidableInstances #-} {-# LANGUAGE FlexibleInstances, UndecidableInstances, FlexibleContexts #-}
module Petzval.Types(Calcuable) where module Petzval.Types(Calcuable) where
import Numeric.AD.Mode import Numeric.AD.Mode

View File

@@ -38,8 +38,10 @@ executable petzval-hs
ad, ad,
linear, linear,
lens, lens,
criterion, mtl,
-- criterion,
hmatrix, hmatrix,
data-default,
petzval-hs petzval-hs
hs-source-dirs: app hs-source-dirs: app
@@ -48,10 +50,12 @@ executable petzval-prof
main-is: Main.hs main-is: Main.hs
build-depends: base, build-depends: base,
ad, ad,
mtl,
linear, linear,
lens, lens,
criterion, -- criterion,
hmatrix, hmatrix,
data-default,
petzval-hs petzval-hs
hs-source-dirs: app hs-source-dirs: app
ghc-options: ghc-options:
@@ -83,4 +87,5 @@ library
deepseq, deepseq,
containers, containers,
monad-loops, monad-loops,
hmatrix hmatrix,
data-default