hnetcdf-0.2.0.0: Data/NetCDF/Metadata.hs
{-# LANGUAGE FlexibleInstances, UndecidableInstances, EmptyDataDecls #-}
-- | NetCDF file metadata handling: when a NetCDF file is opened,
-- metadata defining the dimensions, variables and attributes in the
-- file are read all at once to create a value of type `NcInfo`.
module Data.NetCDF.Metadata
( Name
, NcDim (..)
, NcAttr (..), ToNcAttr (..), FromNcAttr (..)
, NcVar (..)
, NcInfo (..), NcRead, NcWrite
, ncDim, ncAttr, ncVar, ncVarAttr
, emptyNcInfo
, addNcDim, addNcVar, addNcAttr, addNcVarAttr, (#)
) where
import Data.NetCDF.Types
import qualified Data.Map as M
import Data.Word
import Foreign.C
-- | Names for dimensions, variables, attributes.
type Name = String
-- | Information about a dimension: name, number of entries and
-- whether unlimited.
data NcDim = NcDim { ncDimName :: Name
, ncDimLength :: Int
, ncDimUnlimited :: Bool
} deriving Show
-- | Attribute value.
data NcAttr = NcAttrByte [Word8]
| NcAttrChar [Char]
| NcAttrShort [CShort]
| NcAttrInt [CInt]
| NcAttrFloat [CFloat]
| NcAttrDouble [CDouble]
deriving (Eq, Show)
-- | Conversion from Haskell types to attribute values.
class ToNcAttrHelp a where
toAttrHelp :: [a] -> NcAttr
instance ToNcAttrHelp Word8 where toAttrHelp = NcAttrByte
instance ToNcAttrHelp Char where toAttrHelp = NcAttrChar
instance ToNcAttrHelp CShort where toAttrHelp = NcAttrShort
instance ToNcAttrHelp CInt where toAttrHelp = NcAttrInt
instance ToNcAttrHelp CFloat where toAttrHelp = NcAttrFloat
instance ToNcAttrHelp CDouble where toAttrHelp = NcAttrDouble
class ToNcAttr a where
toAttr :: a -> NcAttr
instance ToNcAttrHelp a => ToNcAttr a where
toAttr x = toAttrHelp [x]
instance ToNcAttrHelp a => ToNcAttr [a] where
toAttr xs = toAttrHelp xs
-- | Conversion from attribute values to Haskell types.
class FromNcAttr a where
fromAttr :: NcAttr -> Maybe a
instance FromNcAttr Word8 where
fromAttr (NcAttrByte [x]) = Just x
fromAttr _ = Nothing
instance FromNcAttr [Word8] where
fromAttr (NcAttrByte xs) = Just xs
fromAttr _ = Nothing
instance FromNcAttr Char where
fromAttr (NcAttrChar [x]) = Just x
fromAttr _ = Nothing
instance FromNcAttr [Char] where
fromAttr (NcAttrChar xs) = Just xs
fromAttr _ = Nothing
instance FromNcAttr CShort where
fromAttr (NcAttrShort [x]) = Just x
fromAttr _ = Nothing
instance FromNcAttr [CShort] where
fromAttr (NcAttrShort xs) = Just xs
fromAttr _ = Nothing
instance FromNcAttr CInt where
fromAttr (NcAttrInt [x]) = Just x
fromAttr _ = Nothing
instance FromNcAttr [CInt] where
fromAttr (NcAttrInt xs) = Just xs
fromAttr _ = Nothing
instance FromNcAttr CFloat where
fromAttr (NcAttrFloat [x]) = Just x
fromAttr _ = Nothing
instance FromNcAttr [CFloat] where
fromAttr (NcAttrFloat xs) = Just xs
fromAttr _ = Nothing
instance FromNcAttr CDouble where
fromAttr (NcAttrDouble [x]) = Just x
fromAttr _ = Nothing
instance FromNcAttr [CDouble] where
fromAttr (NcAttrDouble xs) = Just xs
fromAttr _ = Nothing
-- | Information about a variable: name, type, dimensions and
-- attributes.
data NcVar = NcVar { ncVarName :: Name
, ncVarType :: NcType
, ncVarDims :: [NcDim]
, ncVarAttrs :: M.Map Name NcAttr
} deriving Show
-- | Type tags for NcInfo values.
data NcRead
data NcWrite
-- | Metadata information for a whole NetCDF file.
data NcInfo a = NcInfo { ncName :: FilePath
-- ^ File name.
, ncDims :: M.Map Name NcDim
-- ^ Dimensions defined in file.
, ncVars :: M.Map Name NcVar
-- ^ Variables defined in file.
, ncAttrs :: M.Map Name NcAttr
-- ^ Global attributes defined in file.
, ncId :: NcId
-- ^ Low-level file access ID.
, ncVarIds :: M.Map Name NcId
-- ^ Low-level IDs for variables.
} deriving Show
-- | Extract dimension metadata by name.
ncDim :: NcInfo a -> Name -> Maybe NcDim
ncDim nc n = M.lookup n $ ncDims nc
-- | Extract a global attribute by name.
ncAttr :: NcInfo a -> Name -> Maybe NcAttr
ncAttr nc n = M.lookup n $ ncAttrs nc
-- | Extract variable metadata by name.
ncVar :: NcInfo a -> Name -> Maybe NcVar
ncVar nc n = M.lookup n $ ncVars nc
-- | Extract an attribute for a given variable by name.
ncVarAttr :: NcVar -> Name -> Maybe NcAttr
ncVarAttr v n = M.lookup n $ ncVarAttrs v
-- | Empty NcInfo value to build on.
emptyNcInfo :: FilePath -> NcInfo NcWrite
emptyNcInfo n = NcInfo n M.empty M.empty M.empty ncInvalidId M.empty
-- | Add a new dimension to an NcInfo value.
addNcDim :: NcDim -> NcInfo NcWrite -> NcInfo NcWrite
addNcDim dim@(NcDim name _ _) (NcInfo n ds vs as fid vids) =
NcInfo n (M.insert name chkdim ds) vs as fid vids
where chkdim = dim { ncDimUnlimited =
ncDimUnlimited dim &&
(not . or . (map ncDimUnlimited) . M.elems $ ds) }
-- | Add a new variable to an NcInfo value.
addNcVar :: NcVar -> NcInfo NcWrite -> NcInfo NcWrite
addNcVar var@(NcVar name _ _ _) (NcInfo n ds vs as fid vids) =
NcInfo n ds (M.insert name var vs) as fid vids
-- | Add a new global attribute to an NcInfo value.
addNcAttr :: Name -> NcAttr -> NcInfo NcWrite -> NcInfo NcWrite
addNcAttr name att (NcInfo n ds vs as fid vids) =
NcInfo n ds vs (M.insert name att as) fid vids
-- | Add a new attribute to an NcVar value.
addNcVarAttr :: Name -> NcAttr -> NcVar -> NcVar
addNcVarAttr name att (NcVar n t ds as) = NcVar n t ds (M.insert name att as)
infixl 8 #
-- | Handy postfix function application.
(#) :: a -> (a -> b) -> b
(#) = flip ($)