packages feed

flowsim-0.2.6: src/CloneSim.hs

{- | CloneSim - fragment a genome sequence to simulate cloning
     Factored out from flowsim in order to separate clone generation
     from flow simulation and base calling.
-}

{-# Language DeriveDataTypeable #-}

module Main where

import Bio.Sequence hiding ((!))
import Statistics

import System.IO (stdin,stdout,stderr,hPutStrLn)
import Control.Monad (forM)
import qualified Data.ByteString.Lazy as B
import Data.Int (Int64)
import System.Console.CmdArgs
import Data.Array

type Dist    = String
data Conf = Conf 
            { lengths :: Dist
            , count :: Int
            , input :: [FilePath]
            } deriving (Data,Typeable,Show)

modes :: Mode Conf
modes = mode $ Conf {  
    lengths = "Uniform 400 800" &= text "model for clone lengths" & typ "DIST"
  , count = 10                &= text "number of reads to generate" & typ "INT"
  , input = def &= args & typFile
  } &= prog "clonesim"
    & text "simulate sequence cloning"
    & helpSuffix ["Available distributions (DIST):" 
                 ,"    Uniform a b, Normal mu sigma, LogNormal mu sigma"]

version :: String
version = "clonesim v0.2.6, copyright 2010 Ketil Malde" 

data Dir   = Fwd | Rev deriving (Eq,Enum,Bounded)

instance Random Dir where 
  random g = let (b,g') = random g in (if b then Fwd else Rev,g')
  randomR = error "randomR is undefined for Dir"

main :: IO ()
main = do
  conf <- cmdArgs version [modes]
  -- print conf
  let inf = case input conf of 
        []  -> hPutStrLn stderr "clonesim: reading from stdin" >> hReadFasta stdin
        [x] -> readFasta x
        _   -> error "Please specify only a single input file"
  ss <- map (defragSeq . castToNuc) `fmap` inf
  let sa = listArray (0,length ss-1) ss
  hWriteFasta stdout =<< evalRandIO (simulate conf sa)
  
type SeqArray = Array Int (Sequence Nuc)

-- | the real 'main'
simulate :: RandomGen g => Conf -> SeqArray -> Rand g [Sequence Nuc]
simulate conf sa = do
  let ldist   = read $ lengths conf
      (_,asz) = bounds sa
  forM [1..count conf] $ const 
    (do i <- floor `fmap` sample (Uniform 0 $ 1+fromIntegral asz) -- inclusive?
        let s = sa!i
        p <- round `fmap` sample (Uniform 0 $ fromIntegral (seqlength s-1))
        l <- round `fmap` sample ldist
        dir <- getRandom
        return (mkClone dir p l s))
    
mkClone :: Dir -> Int64 -> Int64 -> Sequence Nuc -> Sequence Nuc
mkClone dir pos len (Seq h s mq) = 
  Seq (fromStr (toStr h++" "++show pos++case dir of Fwd -> "+"; Rev -> "-"))
      sd
      qual
    where sd = B.take len
               . (case dir of Fwd -> snd; Rev -> revcompl' . fst) 
               . B.splitAt pos $ s
          qual = B.take len `fmap` case dir of Fwd -> fst; Rev -> snd 
                 `fmap` B.splitAt pos `fmap` mq