fits-parse-0.3.1: src/Data/Fits/Read.hs
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
module Data.Fits.Read where
import Control.Exception ( displayException )
import Data.Bifunctor ( first )
import Data.ByteString ( ByteString )
import Data.Maybe ( listToMaybe )
import Data.Text ( Text, unpack )
import qualified Data.ByteString as BS
import qualified Data.Map.Lazy as Map
import qualified Text.Megaparsec as M
import Data.List ( find )
---- local imports
import Data.Fits as Fits
import Data.Fits.MegaParser (ParseErr(..), parseHDU, parseHDUs)
import Data.Fits (HeaderDataUnit(..))
-- | Parse and read all HDUs in the input string
readHDUs :: ByteString -> Either String [HeaderDataUnit]
readHDUs bs = do
first (show . ParseError) $ M.runParser parseHDUs "FITS" bs
-- | Parse and read only the Primary HDU from the input string
readPrimaryHDU :: ByteString -> Either String HeaderDataUnit
readPrimaryHDU bs = do
first (show . ParseError) $ M.runParser parseHDU "FITS" bs
-- | Look up a keyword and parse it into the expected format
getKeyword :: Text -> (Value -> Maybe a) -> HeaderDataUnit -> Either String a
getKeyword k fromVal hdu = do
let key = Keyword k
v <- maybeError (MissingKey key) $ Map.lookup key (_keywords . _header $ hdu)
maybeError (InvalidKey key v) $ fromVal v
where
findKey :: Keyword -> Header -> Maybe Value
findKey key h = Map.lookup key (_keywords h)
-- | Get the HDU at an index and fail with a readable error
getHDU :: String -> Int -> [HeaderDataUnit] -> Either String HeaderDataUnit
getHDU name n hdus = do
maybeError (MissingHDU name n) $ listToMaybe $ drop n hdus
maybeError :: FitsError -> Maybe a -> Either String a
maybeError e Nothing = Left (show e)
maybeError _ (Just a) = Right a
eitherFail :: MonadFail m => Either String a -> m a
eitherFail (Left e) = fail e
eitherFail (Right a) = return a
data FitsError
= ParseError ParseErr
| MissingKey Keyword
| InvalidKey Keyword Value
| MissingHDU String Int
| InvalidData String
deriving (Eq)
instance Show FitsError where
show (ParseError e) = displayException e
show (MissingKey (Keyword k)) = "Keyword Missing: " <> unpack k
show (InvalidKey (Keyword k) val) = "Keyword: " <> unpack k <> " was invalid. Got " <> show val
show (MissingHDU name n) = "HDU Missing: " <> name <> " at index " <> show n
show (InvalidData err) = "Data Invalid: " <> err
-- -- | An example of how to use the library
-- example :: IO ()
-- example = do
-- bs <- BS.readFile "./fits_files/nso_dkist.fits"
--
-- (tel, obs, dm) <- throwLeft $ exampleReadMyData bs
--
-- putStrLn $ "TELESCOPE: " <> unpack tel
-- putStrLn $ "OBSERVATORY: " <> unpack obs
-- putStrLn $ "DATAMIN: " <> show dm
--
-- where
-- throwLeft :: Show e => Either e a -> IO a
-- throwLeft (Left e) = fail $ show e
-- throwLeft (Right a) = return a
--
-- -- You can parse the file and lookup relevant data in the same function
-- exampleReadMyData :: ByteString -> Either String (Text, Text, Float)
-- exampleReadMyData bs = do
-- hdus <- readHDUs bs
-- hdu <- getHDU "Main Binary Table" 1 hdus
-- tel <- getKeyword "TELESCOP" toText hdu
-- obs <- getKeyword "OBSRVTRY" toText hdu
-- dm <- getKeyword "DATAMIN" toFloat hdu
-- return (tel, obs, dm)
--