packages feed

sequenceTools-1.6.0.0: src/SequenceTools/Utils.hs

{-# LANGUAGE OverloadedStrings #-}
module SequenceTools.Utils (versionInfoOpt, versionInfoText, sampleWithoutReplacement,
    freqSumToEigenstrat, dosageToEigenstratGeno, UserInputException(..)) where

import           SequenceFormats.Eigenstrat (EigenstratSnpEntry (..),
                                             GenoEntry (..), GenoLine)
import           SequenceFormats.FreqSum    (FreqSumEntry (..))
import           SequenceFormats.Utils      (Chrom (..))

import           Control.Exception          (Exception)
import qualified Data.ByteString.Char8      as B
import           Data.Vector                (fromList)
import           Data.Version               (showVersion)
import qualified Options.Applicative        as OP
import           Paths_sequenceTools        (version)
import           System.Random              (randomRIO)

data UserInputException = UserInputException String deriving (Show)
instance Exception UserInputException

versionInfoOpt :: OP.Parser (a -> a)
versionInfoOpt = OP.infoOption (showVersion version) (OP.long "version" <> OP.help "Print version and exit")

versionInfoText :: String
versionInfoText = "This tool is part of sequenceTools version " ++ showVersion version

sampleWithoutReplacement :: [a] -> Int -> IO (Maybe [a])
sampleWithoutReplacement = go []
  where
    go res _ 0 = return $ Just res
    go res xs n
        | n > length xs = return Nothing
        | n == length xs = return $ Just (xs ++ res)
        | otherwise = do
                rn <- randomRIO (0, length xs - 1)
                let a = xs !! rn
                    xs' = remove rn xs
                go (a:res) xs' (n - 1)
    remove i xs = let (ys, zs) = splitAt i xs in ys ++ tail zs

-- |convert a freqSum entry to an eigenstrat SNP entry
freqSumToEigenstrat :: FreqSumEntry -> (EigenstratSnpEntry, GenoLine)
freqSumToEigenstrat (FreqSumEntry chrom@(Chrom c) pos maybeSnpId maybeGeneticPos ref alt calls) =
    let snpId_ = case maybeSnpId of
            Just id_ -> id_
            Nothing  -> c <> "_" <> B.pack (show pos)
        geneticPos = case maybeGeneticPos of
            Just p  -> p
            Nothing -> 0.0
        snpEntry = EigenstratSnpEntry chrom pos geneticPos snpId_ ref alt
        geno = fromList . map dosageToEigenstratGeno $ calls
    in  (snpEntry, geno)

-- |convert a Dosage to an eigenstrat-encoded genotype
dosageToEigenstratGeno :: Maybe (Int, Int) -> GenoEntry
dosageToEigenstratGeno Nothing       = Missing
dosageToEigenstratGeno (Just (0, 1)) = HomRef
dosageToEigenstratGeno (Just (1, 1)) = HomAlt
dosageToEigenstratGeno (Just (0, 2)) = HomRef
dosageToEigenstratGeno (Just (1, 2)) = Het
dosageToEigenstratGeno (Just (2, 2)) = HomAlt
dosageToEigenstratGeno c             = error ("unknown genotype " ++ show c)