packages feed

biohazard-0.6.1: tools/count-coverage.hs

{-# LANGUAGE BangPatterns, NoMonomorphismRestriction, FlexibleContexts #-}
import Bio.Bam.Header
import Bio.Bam.Reader
import Bio.Bam.Rec
import Bio.Base
import Bio.Iteratee
import Data.Version ( showVersion )
import Paths_biohazard ( version )
import System.Environment
import System.Exit
import System.IO ( hPutStr )

main :: IO ()
main = do
    mq <- getArgs >>= \args -> case (args, reads (head args)) of
            ([ ], _)        -> return (Q 0)
            ([_], [(x,[])]) -> return (Q x)
            _               -> do pn <- getProgName
                                  hPutStr stderr $ pn ++ ", version " ++ showVersion version
                                                ++ "\nUsage: " ++ pn ++ "[<min-mapq>]\n"
                                  exitFailure

    let putLine nm cv = putStr $ nm ++ '\t' : shows cv "\n"

        printOne :: Refs -> (Refseq, Int) -> IO ()
        printOne refs (r,c) = putLine (unpackSeqid (sq_name (getRef refs r))) c

        do_count :: Monad m => Iteratee [(a,Int)] m Int
        do_count = foldStream (\a -> (+) a . snd) 0

    (total,()) <- enumHandle defaultBufSize stdin >=> run                                   $
                  joinI $ decodeAnyBam                                                      $ \hdr ->
                  joinI $ mapMaybeStream ( \br -> case unpackBam br of
                        b | not (isUnmapped b) && b_mapq b >= mq
                            -> Just $! P (b_rname b) (b_pos b) (alignedLength (b_cigar b))
                        _   -> Nothing )                                                    $
                  joinI $ groupStreamOn ref count_cov                                       $
                  zipStreams do_count (mapStreamM_ $ printOne $ meta_refs hdr)

    putLine "total" total

data P = P { ref :: !Refseq, pos :: !Int, alen :: !Int }

count_cov :: Monad m => a -> m (Iteratee [P] m Int)
count_cov _ = return $ liftI $ step 0
  where
    step !a (EOF ex) = idone a (EOF ex)
    step !a (Chunk [    ]) = liftI $ step a
    step !a (Chunk (r:rs)) = extend a (pos r) (pos r + alen r) (Chunk rs)

    extend !a !u !v (EOF ex) = idone (a+v-u) (EOF ex)
    extend !a !u !v (Chunk [    ]) = liftI $ extend a u v
    extend !a !u !v (Chunk (r:rs))
        | pos r <= v = extend a u (max v (pos r + alen r)) (Chunk rs)
        | otherwise  = step (a+v-u) (Chunk (r:rs))