simseq-0.0: src/Options.hs
{- Handle Options
Options:
--prime model for starting points [uniform]
--error error model [uniform,gradient,..]
--terminator termination condition [sigma..]
--model shortcut for useful combinations [sanger|454|solexa]
-}
module Options where
import System.Environment (getArgs)
import System.Exit (exitWith,ExitCode(..))
import System.Console.GetOpt
import System.IO
import Data.List (unfoldr)
import Control.Monad (when)
import Bio.Sequence
import UnfoldMut
import Sanger
import R454
version, usagemsg :: String
version = "0.0"
usagemsg = "Usage: simseq [options] FILE.."
data Opts = Opts { primer :: Primer
, errmod :: [Mutator]
, term :: Terminator
}
getOpts :: IO (Opts,[Sequence])
getOpts = do
(opt1,fs,err) <- getArgs >>= (return . getOpt Permute options)
opts <- parseargs opt1
when (not $ null err) (error $ usage err)
when (forceOpts opts) (error "Impossible!")
ss <- if null fs then hReadFasta stdin
else return . concat =<< mapM readFasta fs
return (opts, ss)
where
forceOpts (Opts x y z) = x `seq` y `seq` z `seq` False
parseargs :: [Opts -> IO Opts] -> IO Opts
parseargs args = foldl (>>=) (return defaultopts) args
usage :: [String] -> String
usage errs = usageInfo (concat errs ++ usagemsg) options
------------------------------------------------------------
options :: [OptDescr (Opts -> IO Opts)]
options = [ Option [] ["primer"] (ReqArg (setPrimer . processArgs) "p")
("Model for initiating sequencing "++show (map fst primers))
, Option [] ["error"] (ReqArg (setMutator . processArgs) "e")
("Error model "++show (map fst mutators))
, Option [] ["terminator"] (ReqArg (setTerm . processArgs) "t")
("Termination condition "++show (map fst terminators))
, Option [] ["model"] (ReqArg (setModel . processArgs) "m")
("Shortcut for useful combinations "++show (map fst models))
, Option ['h'] ["help"] (ReqArg help "option") ("Help with 'option'")
]
defaultopts :: Opts
defaultopts = Opts (error "no primer specified")
(error "no error model specified")
(error "no terminator specified")
help :: String -> Opts -> IO Opts
help arg _ = do putStrLn usagemsg
case arg of
"primer" -> list "specifies when sequence generation starts" primers
"error" -> list "adds an error model for sequence generation" mutators
"terminator" -> list "specifies when sequence generation terminates" terminators
"model" -> list "specifies a complete model including primer, error model, and terminator" models
_ -> putStrLn (" "++arg++": no such option")
exitWith ExitSuccess
where list str tbl = putStrLn (" "++arg ++ ": "++str++"\n Valid alternatives are: "++unwords (map fst tbl))
------------------------------------------------------------
-- | Break a string argument representing a function and arguments
-- into components. Syntax is func:arg1,arg2,..
processArgs :: String -> (String,[String])
processArgs ss = let (fn,as) = break (==':') ss
in (fn,splitStr ',' as)
splitStr :: Char -> String -> [String]
splitStr c = unfoldr (\s -> if null s then Nothing
else let (x,y) = break (==c) (drop 1 s)
in Just (x,y))
------------------------------------------------------------
-- Lookup tables for selecting the desired behavior
------------------------------------------------------------
notfound :: String -> [(String,a)] -> String -> String
notfound what whats which = "'"++which++"': no such "++what++".\n"++
"Available "++what++"s are: "++ (unwords $ map fst whats)
setPrimer :: (String,[String]) -> Opts -> IO Opts
setPrimer (prim,args) (Opts _ m t) = return (Opts p m t)
where p = maybe (error $ notfound "primer" primers prim)
(\f -> f args) (lookup prim primers)
primers :: [(String,[String]->Primer)]
primers = [("uniform",p_uniform)]
-- help text? "uniform:n,p","select n random starting points, with probability p of forward direction, 1-p or reverse"
------------------------------------------------------------
setTerm :: (String,[String]) -> Opts -> IO Opts
setTerm (trm,args) (Opts p m _) = return (Opts p m t)
where t = maybe (error $ notfound "terminator" terminators trm)
(\f -> f args) (lookup trm terminators)
terminators :: [(String,[String]->Terminator)]
terminators =
[("sigma",\args -> case args of
[s,w] -> \ (MS _ _ l) -> sigma (read s) (read w) $ fromIntegral l
_ -> error "terminator 'sigma' needs two arguments")
]
------------------------------------------------------------
setMutator :: (String,[String]) -> Opts -> IO Opts
setMutator (mut,args) (Opts p m t) = return (Opts p m' t)
where m' = maybe (error $ notfound "mutator" mutators mut)
(\f -> f args : m) (lookup mut mutators)
mutators :: [(String,[String]->Mutator)]
mutators = [] -- ("uniform",...)]
------------------------------------------------------------
setModel :: (String,[String]) -> Opts -> IO Opts
setModel (md,args) _ = return (maybe (error $ notfound "model" models md)
(\f -> case f args of (p,m,t) -> Opts {primer=p,errmod=m,term=t})
(lookup md models))
models :: [(String,[String]->Model)]
models = [("sanger",sanger)
,("stest",\[] -> sanger ["1","1"])
,("454",r454)
]