{- | Module : Data.Matrix.SeitzSymbol.Parser Copyright : (c) Jun Narumi 2020 License : MIT Maintainer : narumij@gmail.com Stability : experimental Seitz Symbol parser and etc. [References] A. Michael Glazer et al. Seitz symbols Acta Cryst. (2014). A70 ネスポロ マッシモ:日本結晶学会誌 59,210-222(2017). https://www.jstage.jst.go.jp/article/jcrsj/59/5/59_210/_pdf -} module Data.Matrix.SeitzSymbol.Parser ( SeitzSymbol(..), seitzSymbol, toMatrix, toSeitzSymbol, toString, ) where import Data.Ratio (Ratio(..),(%)) import Text.Parsec import Text.Parsec.String (Parser) import Data.Ratio.Slash (Slash(..)) import Data.Matrix (Matrix(..),fromLists,toList,submatrix) import Data.Matrix.AsXYZ (fromXYZ) import qualified Data.Matrix as M ((<->),(<|>)) import Data.Matrix.SymmetryOperationsSymbols.Common (properMatricesForPointGroup,MatrixForPointGroupCorrespondingSymmetryElement(..)) type SeitzSymbol a = (String,String,(a,a,a),(Ratio a,Ratio a,Ratio a)) optionSpaces :: Parser () optionSpaces = skipMany space identity :: Parser String identity = do char '1' return "1" symbol :: Parser (String,String) symbol = try irot <|> try rot <|> miller <|> two where sign = oneOf "-+" rot = do a <- oneOf "346" b <- sign return (a:[],b:[]) two = do char '2' return ("2","") miller = do char 'm' return ("m","") irot = do char '-' a <- oneOf "346" b <- sign return ('-':a:[],b:[]) zero :: Num a => Parser a zero = do char '0' return 0 one :: Num a => Parser a one = do char '1' return 1 two :: Num a => Parser a two = do char '2' return 2 minus :: Num a => Parser a minus = do string "-1" return (-1) d :: Num a => Parser a d = do a <- (zero <|> one <|> two <|> minus) return a orientation :: Num a => Parser (a,a,a) orientation = try a <|> b where a = do char '[' a <- d b <- d c <- d char ']' return (a,b,c) b = do a <- d b <- d c <- d return (a,b,c) num :: (Num a, Read a) => Parser a num = do x <- oneOf "123456789" xs <- many digit return $ read (x : xs) int :: (Integral a, Read a) => Parser a int = zero <|> num fract :: (Integral a, Read a) => Parser (Ratio a) fract = do n <- int char '/' d <- int return $ n % d integer :: (Integral a, Read a) => Parser (Ratio a) integer = do i <- int return (i%1) number :: (Integral a, Read a) => Parser (Ratio a) number = do try fract <|> integer matrixPart :: Num a => Parser (String,String,(a,a,a)) matrixPart = try a <|> b where a = do (sy,si) <- symbol spaces o <- orientation return (sy,si,o) b = do s <- identity return (s,"",(0,0,0)) seitzSymbol :: (Integral a, Read a) => Parser (SeitzSymbol a) seitzSymbol = do char '{' optionSpaces (sy,si,o) <- matrixPart optionSpaces char '|' optionSpaces p <- number spaces q <- number spaces r <- number optionSpaces char '}' return (sy,si,o,(p,q,r)) toMatrix :: (Integral a,Read a) => [MatrixForPointGroupCorrespondingSymmetryElement a] -> SeitzSymbol a -> Maybe (Matrix (Ratio a)) toMatrix tbl (sy,si,(o1,o2,o3),(p,q,r)) = build p q r <$> result where transformCoordinate (_,_,symbolLabel,sense,_,orientation,transformedCoordinate,_) = ( (symbolLabel,sense,if null orientation then [0,0,0] else orientation), transformedCoordinate ) result = lookup (sy,si,[o1,o2,o3]) $ map transformCoordinate tbl build p q r xyz = _W M.<|> _w M.<-> fromLists [[0,0,0,1]] where _W = submatrix 1 3 1 3 . fromXYZ $ xyz _w = fromLists [[p],[q],[r]] toString :: (Integral a, Show a) => SeitzSymbol a -> String toString ("1",si,(o1,o2,o3),(p,q,r)) = "{ " ++ "1" ++ " | " ++ show (Slash p) ++ " " ++ show (Slash q) ++ " " ++ show (Slash r) ++ " }" toString (sy,si,(o1,o2,o3),(p,q,r)) = "{ " ++ sy ++ si ++ " " ++ show o1 ++ show o2 ++ show o3 ++ " | " ++ show (Slash p) ++ " " ++ show (Slash q) ++ " " ++ show (Slash r) ++ " }" toSeitzSymbol :: Integral a => Matrix (Ratio a) -> Maybe (SeitzSymbol a) toSeitzSymbol m = lookup w $ map tt properMatricesForPointGroup where getW = submatrix 1 3 1 3 getw = submatrix 1 3 4 4 w = getW m p:q:r:[] = toList . getw $ m tt (_,_,symbolLabel,sense,_,(o1:o2:o3:_),transformedCoordinate,_) = (getW . fromXYZ $ transformedCoordinate, (symbolLabel,sense,(o1,o2,o3),(p,q,r))) tt (_,_,symbolLabel,sense,_,[],transformedCoordinate,_) = (getW . fromXYZ $ transformedCoordinate, (symbolLabel,sense,(0,0,0),(p,q,r)))