packages feed

RNAlien 1.3.7 → 1.6.0

raw patch · 18 files changed

+3373/−3223 lines, 18 filesdep +BiobaseBlastdep +BiobaseFastadep +BiobaseHTTPdep −EntrezHTTPdep −biocoredep −biofastadep ~BlastHTTPdep ~Taxonomydep ~networksetup-changedPVP ok

version bump matches the API change (PVP)

Dependencies added: BiobaseBlast, BiobaseFasta, BiobaseHTTP, BiobaseTypes

Dependencies removed: EntrezHTTP, biocore, biofasta, blastxml

Dependency ranges changed: BlastHTTP, Taxonomy, network

API changes (from Hackage documentation)

- Bio.InfernalParser: parseCMSearch :: String -> Either ParseError CMsearch
- Bio.InfernalParser: parseCMSearches :: String -> Either ParseError CMsearch
- Bio.InfernalParser: parseCMstat :: String -> Either ParseError CMstat
- Bio.InfernalParser: readCMSearch :: String -> IO (Either ParseError CMsearch)
- Bio.InfernalParser: readCMSearches :: String -> IO (Either ParseError CMsearch)
- Bio.InfernalParser: readCMstat :: String -> IO (Either ParseError CMstat)
- Bio.RNAcentralHTTP: RNAcentralEntry :: Text -> Text -> Text -> Text -> Int -> Text -> Text -> RNAcentralEntry
- Bio.RNAcentralHTTP: RNAcentralEntryResponse :: Int -> Maybe Text -> Maybe Text -> [RNAcentralEntry] -> RNAcentralEntryResponse
- Bio.RNAcentralHTTP: [count] :: RNAcentralEntryResponse -> Int
- Bio.RNAcentralHTTP: [length] :: RNAcentralEntry -> Int
- Bio.RNAcentralHTTP: [md5] :: RNAcentralEntry -> Text
- Bio.RNAcentralHTTP: [next] :: RNAcentralEntryResponse -> Maybe Text
- Bio.RNAcentralHTTP: [previous] :: RNAcentralEntryResponse -> Maybe Text
- Bio.RNAcentralHTTP: [publications] :: RNAcentralEntry -> Text
- Bio.RNAcentralHTTP: [results] :: RNAcentralEntryResponse -> [RNAcentralEntry]
- Bio.RNAcentralHTTP: [rnacentral_id] :: RNAcentralEntry -> Text
- Bio.RNAcentralHTTP: [sequence] :: RNAcentralEntry -> Text
- Bio.RNAcentralHTTP: [url] :: RNAcentralEntry -> Text
- Bio.RNAcentralHTTP: [xrefs] :: RNAcentralEntry -> Text
- Bio.RNAcentralHTTP: buildSequenceViaMD5Query :: Sequence -> String
- Bio.RNAcentralHTTP: buildStringViaMD5Query :: String -> String
- Bio.RNAcentralHTTP: data RNAcentralEntry
- Bio.RNAcentralHTTP: data RNAcentralEntryResponse
- Bio.RNAcentralHTTP: getRNACentralEntries :: [String] -> IO [Either String RNAcentralEntryResponse]
- Bio.RNAcentralHTTP: instance Data.Aeson.Types.FromJSON.FromJSON Bio.RNAcentralHTTP.RNAcentralEntry
- Bio.RNAcentralHTTP: instance Data.Aeson.Types.FromJSON.FromJSON Bio.RNAcentralHTTP.RNAcentralEntryResponse
- Bio.RNAcentralHTTP: instance Data.Aeson.Types.ToJSON.ToJSON Bio.RNAcentralHTTP.RNAcentralEntry
- Bio.RNAcentralHTTP: instance Data.Aeson.Types.ToJSON.ToJSON Bio.RNAcentralHTTP.RNAcentralEntryResponse
- Bio.RNAcentralHTTP: instance GHC.Classes.Eq Bio.RNAcentralHTTP.RNAcentralEntry
- Bio.RNAcentralHTTP: instance GHC.Classes.Eq Bio.RNAcentralHTTP.RNAcentralEntryResponse
- Bio.RNAcentralHTTP: instance GHC.Generics.Generic Bio.RNAcentralHTTP.RNAcentralEntry
- Bio.RNAcentralHTTP: instance GHC.Generics.Generic Bio.RNAcentralHTTP.RNAcentralEntryResponse
- Bio.RNAcentralHTTP: instance GHC.Show.Show Bio.RNAcentralHTTP.RNAcentralEntry
- Bio.RNAcentralHTTP: instance GHC.Show.Show Bio.RNAcentralHTTP.RNAcentralEntryResponse
- Bio.RNAcentralHTTP: rnaCentralHTTP :: String -> IO (Either String RNAcentralEntryResponse)
- Bio.RNAcentralHTTP: showRNAcentralAlienEvaluation :: [Either String RNAcentralEntryResponse] -> String
- Bio.RNAlienData: CMsearch :: String -> String -> String -> [CMsearchHit] -> CMsearch
- Bio.RNAlienData: CMsearchHit :: Int -> Char -> Double -> Double -> Double -> ByteString -> Int -> Int -> Char -> ByteString -> ByteString -> Double -> ByteString -> CMsearchHit
- Bio.RNAlienData: CMstat :: Int -> String -> String -> Int -> Double -> Int -> Int -> Int -> Int -> String -> Double -> Double -> CMstat
- Bio.RNAlienData: ModelConstruction :: Int -> Sequence -> [TaxonomyRecord] -> Maybe Int -> Maybe Taxon -> Double -> Bool -> [Sequence] -> [SearchResult] -> ModelConstruction
- Bio.RNAlienData: SearchResult :: [(Sequence, Int, ByteString)] -> Maybe Double -> SearchResult
- Bio.RNAlienData: SequenceRecord :: Sequence -> Int -> ByteString -> SequenceRecord
- Bio.RNAlienData: StaticOptions :: String -> String -> Double -> Maybe Int -> Bool -> String -> Int -> Bool -> Bool -> Bool -> Int -> Maybe String -> Maybe String -> Bool -> StaticOptions
- Bio.RNAlienData: TaxonomyRecord :: Int -> [SequenceRecord] -> TaxonomyRecord
- Bio.RNAlienData: [aligned] :: SequenceRecord -> Int
- Bio.RNAlienData: [alignmentModeInfernal] :: ModelConstruction -> Bool
- Bio.RNAlienData: [blastDatabaseSize] :: SearchResult -> Maybe Double
- Bio.RNAlienData: [blastDatabase] :: StaticOptions -> Maybe String
- Bio.RNAlienData: [blastSoftmaskingToggle] :: StaticOptions -> Bool
- Bio.RNAlienData: [candidates] :: SearchResult -> [(Sequence, Int, ByteString)]
- Bio.RNAlienData: [cmsearchHits] :: CMsearch -> [CMsearchHit]
- Bio.RNAlienData: [coverageFilterToggle] :: StaticOptions -> Bool
- Bio.RNAlienData: [cpuThreads] :: StaticOptions -> Int
- Bio.RNAlienData: [evalueThreshold] :: ModelConstruction -> Double
- Bio.RNAlienData: [hitBias] :: CMsearchHit -> Double
- Bio.RNAlienData: [hitDescription] :: CMsearchHit -> ByteString
- Bio.RNAlienData: [hitEnd] :: CMsearchHit -> Int
- Bio.RNAlienData: [hitEvalue] :: CMsearchHit -> Double
- Bio.RNAlienData: [hitGCContent] :: CMsearchHit -> Double
- Bio.RNAlienData: [hitModel] :: CMsearchHit -> ByteString
- Bio.RNAlienData: [hitRank] :: CMsearchHit -> Int
- Bio.RNAlienData: [hitScore] :: CMsearchHit -> Double
- Bio.RNAlienData: [hitSequenceHeader] :: CMsearchHit -> ByteString
- Bio.RNAlienData: [hitSignificance] :: CMsearchHit -> Char
- Bio.RNAlienData: [hitStart] :: CMsearchHit -> Int
- Bio.RNAlienData: [hitStrand] :: CMsearchHit -> Char
- Bio.RNAlienData: [hitTruncation] :: CMsearchHit -> ByteString
- Bio.RNAlienData: [inputFasta] :: ModelConstruction -> Sequence
- Bio.RNAlienData: [iterationNumber] :: ModelConstruction -> Int
- Bio.RNAlienData: [lengthFilterToggle] :: StaticOptions -> Bool
- Bio.RNAlienData: [nSCICutoff] :: StaticOptions -> Double
- Bio.RNAlienData: [nucleotideSequence] :: SequenceRecord -> Sequence
- Bio.RNAlienData: [numberOfWorkerThreads] :: CMsearch -> String
- Bio.RNAlienData: [potentialMembers] :: ModelConstruction -> [SearchResult]
- Bio.RNAlienData: [queryCMfile] :: CMsearch -> String
- Bio.RNAlienData: [queryNumber] :: StaticOptions -> Int
- Bio.RNAlienData: [querySelectionMethod] :: StaticOptions -> String
- Bio.RNAlienData: [recordDescription] :: SequenceRecord -> ByteString
- Bio.RNAlienData: [recordTaxonomyId] :: TaxonomyRecord -> Int
- Bio.RNAlienData: [relativeEntropyCM] :: CMstat -> Double
- Bio.RNAlienData: [relativeEntropyHMM] :: CMstat -> Double
- Bio.RNAlienData: [selectedQueries] :: ModelConstruction -> [Sequence]
- Bio.RNAlienData: [sequenceRecords] :: TaxonomyRecord -> [SequenceRecord]
- Bio.RNAlienData: [sessionID] :: StaticOptions -> String
- Bio.RNAlienData: [singleHitperTaxToggle] :: StaticOptions -> Bool
- Bio.RNAlienData: [statAccession] :: CMstat -> String
- Bio.RNAlienData: [statBasepairs] :: CMstat -> Int
- Bio.RNAlienData: [statBifurcations] :: CMstat -> Int
- Bio.RNAlienData: [statConsensusLength] :: CMstat -> Int
- Bio.RNAlienData: [statEffectiveSequences] :: CMstat -> Double
- Bio.RNAlienData: [statIndex] :: CMstat -> Int
- Bio.RNAlienData: [statModel] :: CMstat -> String
- Bio.RNAlienData: [statName] :: CMstat -> String
- Bio.RNAlienData: [statSequenceNumber] :: CMstat -> Int
- Bio.RNAlienData: [statW] :: CMstat -> Int
- Bio.RNAlienData: [targetSequenceDatabase] :: CMsearch -> String
- Bio.RNAlienData: [taxRecords] :: ModelConstruction -> [TaxonomyRecord]
- Bio.RNAlienData: [taxRestriction] :: StaticOptions -> Maybe String
- Bio.RNAlienData: [taxonomicContext] :: ModelConstruction -> Maybe Taxon
- Bio.RNAlienData: [tempDirPath] :: StaticOptions -> String
- Bio.RNAlienData: [upperTaxonomyLimit] :: ModelConstruction -> Maybe Int
- Bio.RNAlienData: [userTaxId] :: StaticOptions -> Maybe Int
- Bio.RNAlienData: [verbositySwitch] :: StaticOptions -> Bool
- Bio.RNAlienData: data CMsearch
- Bio.RNAlienData: data CMsearchHit
- Bio.RNAlienData: data CMstat
- Bio.RNAlienData: data ModelConstruction
- Bio.RNAlienData: data SearchResult
- Bio.RNAlienData: data SequenceRecord
- Bio.RNAlienData: data StaticOptions
- Bio.RNAlienData: data TaxonomyRecord
- Bio.RNAlienData: instance GHC.Classes.Eq Bio.RNAlienData.CMsearch
- Bio.RNAlienData: instance GHC.Classes.Eq Bio.RNAlienData.CMsearchHit
- Bio.RNAlienData: instance GHC.Classes.Eq Bio.RNAlienData.CMstat
- Bio.RNAlienData: instance GHC.Read.Read Bio.RNAlienData.CMsearch
- Bio.RNAlienData: instance GHC.Read.Read Bio.RNAlienData.CMsearchHit
- Bio.RNAlienData: instance GHC.Read.Read Bio.RNAlienData.CMstat
- Bio.RNAlienData: instance GHC.Show.Show Bio.RNAlienData.CMsearch
- Bio.RNAlienData: instance GHC.Show.Show Bio.RNAlienData.CMsearchHit
- Bio.RNAlienData: instance GHC.Show.Show Bio.RNAlienData.CMstat
- Bio.RNAlienData: instance GHC.Show.Show Bio.RNAlienData.ModelConstruction
- Bio.RNAlienData: instance GHC.Show.Show Bio.RNAlienData.SearchResult
- Bio.RNAlienData: instance GHC.Show.Show Bio.RNAlienData.SequenceRecord
- Bio.RNAlienData: instance GHC.Show.Show Bio.RNAlienData.StaticOptions
- Bio.RNAlienData: instance GHC.Show.Show Bio.RNAlienData.TaxonomyRecord
- Bio.RNAlienLibrary: checkNCBIConnection :: IO (Either String String)
- Bio.RNAlienLibrary: checkTaxonomyRestriction :: Maybe String -> Maybe String
- Bio.RNAlienLibrary: checkTools :: [String] -> String -> String -> IO (Either String String)
- Bio.RNAlienLibrary: cmSearchsubString :: Int -> Int -> String -> String
- Bio.RNAlienLibrary: compareCM :: String -> String -> String -> IO (Either String Double)
- Bio.RNAlienLibrary: constructTaxonomyRecordsCSVTable :: ModelConstruction -> String
- Bio.RNAlienLibrary: createSessionID :: Maybe String -> IO String
- Bio.RNAlienLibrary: evaluateConstructionResult :: StaticOptions -> ModelConstruction -> IO String
- Bio.RNAlienLibrary: evaluePartitionTrimCMsearchHits :: Double -> [(CMsearch, (Sequence, Int, ByteString))] -> ([(CMsearch, (Sequence, Int, ByteString))], [(CMsearch, (Sequence, Int, ByteString))], [(CMsearch, (Sequence, Int, ByteString))])
- Bio.RNAlienLibrary: logEither :: (Show a) => Either a b -> String -> IO ()
- Bio.RNAlienLibrary: logMessage :: String -> String -> IO ()
- Bio.RNAlienLibrary: logToolVersions :: String -> String -> IO ()
- Bio.RNAlienLibrary: modelConstructer :: StaticOptions -> ModelConstruction -> IO ModelConstruction
- Bio.RNAlienLibrary: parseCMSearch :: String -> Either ParseError CMsearch
- Bio.RNAlienLibrary: parseCMstat :: String -> Either ParseError CMstat
- Bio.RNAlienLibrary: preprocessClustalForRNAcodeExternal :: String -> String -> Int -> Int -> Int -> Bool -> IO (Either String (String, String))
- Bio.RNAlienLibrary: preprocessClustalForRNAz :: String -> String -> Int -> Double -> Double -> Bool -> IO (Either String (String, String))
- Bio.RNAlienLibrary: preprocessClustalForRNAzExternal :: String -> String -> Int -> Int -> Int -> Bool -> IO (Either String (String, String))
- Bio.RNAlienLibrary: readCMSearch :: String -> IO (Either ParseError CMsearch)
- Bio.RNAlienLibrary: readCMSearches :: String -> IO (Either ParseError CMsearch)
- Bio.RNAlienLibrary: readCMstat :: String -> IO (Either ParseError CMstat)
- Bio.RNAlienLibrary: reformatFasta :: Sequence -> Sequence
- Bio.RNAlienLibrary: resultSummary :: ModelConstruction -> StaticOptions -> IO ()
- Bio.RNAlienLibrary: rnaZEvalOutput :: Either ParseError RNAz -> String
- Bio.RNAlienLibrary: setInitialTaxId :: Maybe String -> String -> Maybe Int -> Sequence -> IO (Maybe Int)
- Bio.RNAlienLibrary: setVerbose :: Verbosity -> Bool
- Bio.RNAlienLibrary: systemCMsearch :: Int -> String -> String -> String -> String -> IO ExitCode
+ Biobase.RNAlien.InfernalParser: parseCMSearch :: String -> Either ParseError CMsearch
+ Biobase.RNAlien.InfernalParser: parseCMSearches :: String -> Either ParseError CMsearch
+ Biobase.RNAlien.InfernalParser: parseCMstat :: String -> Either ParseError CMstat
+ Biobase.RNAlien.InfernalParser: readCMSearch :: String -> IO (Either ParseError CMsearch)
+ Biobase.RNAlien.InfernalParser: readCMSearches :: String -> IO (Either ParseError CMsearch)
+ Biobase.RNAlien.InfernalParser: readCMstat :: String -> IO (Either ParseError CMstat)
+ Biobase.RNAlien.Library: checkNCBIConnection :: IO (Either String String)
+ Biobase.RNAlien.Library: checkTaxonomyRestriction :: Maybe String -> Maybe String
+ Biobase.RNAlien.Library: checkTools :: [String] -> String -> String -> IO (Either String String)
+ Biobase.RNAlien.Library: cmSearchsubString :: Int -> Int -> String -> String
+ Biobase.RNAlien.Library: compareCM :: String -> String -> String -> IO (Either String Double)
+ Biobase.RNAlien.Library: constructTaxonomyRecordsCSVTable :: ModelConstruction -> String
+ Biobase.RNAlien.Library: createSessionID :: Maybe String -> IO String
+ Biobase.RNAlien.Library: evaluateConstructionResult :: StaticOptions -> ModelConstruction -> IO String
+ Biobase.RNAlien.Library: evaluePartitionTrimCMsearchHits :: Double -> [(CMsearch, (Fasta () (), Int, ByteString))] -> ([(CMsearch, (Fasta () (), Int, ByteString))], [(CMsearch, (Fasta () (), Int, ByteString))], [(CMsearch, (Fasta () (), Int, ByteString))])
+ Biobase.RNAlien.Library: logEither :: Show a => Either a b -> String -> IO ()
+ Biobase.RNAlien.Library: logMessage :: String -> String -> IO ()
+ Biobase.RNAlien.Library: logToolVersions :: String -> String -> IO ()
+ Biobase.RNAlien.Library: modelConstructer :: StaticOptions -> ModelConstruction -> IO ModelConstruction
+ Biobase.RNAlien.Library: parseCMSearch :: String -> Either ParseError CMsearch
+ Biobase.RNAlien.Library: parseCMstat :: String -> Either ParseError CMstat
+ Biobase.RNAlien.Library: preprocessClustalForRNAcodeExternal :: String -> String -> Int -> Int -> Int -> Bool -> IO (Either String (String, String))
+ Biobase.RNAlien.Library: preprocessClustalForRNAz :: String -> String -> Int -> Double -> Double -> Bool -> IO (Either String (String, String))
+ Biobase.RNAlien.Library: preprocessClustalForRNAzExternal :: String -> String -> Int -> Int -> Int -> Bool -> IO (Either String (String, String))
+ Biobase.RNAlien.Library: readCMSearch :: String -> IO (Either ParseError CMsearch)
+ Biobase.RNAlien.Library: readCMSearches :: String -> IO (Either ParseError CMsearch)
+ Biobase.RNAlien.Library: readCMstat :: String -> IO (Either ParseError CMstat)
+ Biobase.RNAlien.Library: readFastaFile :: String -> IO [Fasta () ()]
+ Biobase.RNAlien.Library: reformatFasta :: Fasta () () -> Fasta () ()
+ Biobase.RNAlien.Library: resultSummary :: ModelConstruction -> StaticOptions -> IO ()
+ Biobase.RNAlien.Library: rnaZEvalOutput :: Either ParseError RNAz -> String
+ Biobase.RNAlien.Library: setInitialTaxId :: Bool -> Int -> Maybe String -> String -> Maybe Int -> Fasta () () -> IO (Maybe Int)
+ Biobase.RNAlien.Library: setVerbose :: Verbosity -> Bool
+ Biobase.RNAlien.Library: systemCMsearch :: Int -> String -> String -> String -> String -> IO ExitCode
+ Biobase.RNAlien.Library: writeFastaFile :: String -> [Fasta () ()] -> IO ()
+ Biobase.RNAlien.RNAcentralHTTP: RNAcentralEntry :: Text -> Text -> Text -> Text -> Int -> Text -> Text -> RNAcentralEntry
+ Biobase.RNAlien.RNAcentralHTTP: RNAcentralEntryResponse :: Int -> Maybe Text -> Maybe Text -> [RNAcentralEntry] -> RNAcentralEntryResponse
+ Biobase.RNAlien.RNAcentralHTTP: [count] :: RNAcentralEntryResponse -> Int
+ Biobase.RNAlien.RNAcentralHTTP: [length] :: RNAcentralEntry -> Int
+ Biobase.RNAlien.RNAcentralHTTP: [md5] :: RNAcentralEntry -> Text
+ Biobase.RNAlien.RNAcentralHTTP: [next] :: RNAcentralEntryResponse -> Maybe Text
+ Biobase.RNAlien.RNAcentralHTTP: [previous] :: RNAcentralEntryResponse -> Maybe Text
+ Biobase.RNAlien.RNAcentralHTTP: [publications] :: RNAcentralEntry -> Text
+ Biobase.RNAlien.RNAcentralHTTP: [results] :: RNAcentralEntryResponse -> [RNAcentralEntry]
+ Biobase.RNAlien.RNAcentralHTTP: [rnacentral_id] :: RNAcentralEntry -> Text
+ Biobase.RNAlien.RNAcentralHTTP: [sequence] :: RNAcentralEntry -> Text
+ Biobase.RNAlien.RNAcentralHTTP: [url] :: RNAcentralEntry -> Text
+ Biobase.RNAlien.RNAcentralHTTP: [xrefs] :: RNAcentralEntry -> Text
+ Biobase.RNAlien.RNAcentralHTTP: buildSequenceViaMD5Query :: Fasta () () -> String
+ Biobase.RNAlien.RNAcentralHTTP: buildStringViaMD5Query :: String -> String
+ Biobase.RNAlien.RNAcentralHTTP: data RNAcentralEntry
+ Biobase.RNAlien.RNAcentralHTTP: data RNAcentralEntryResponse
+ Biobase.RNAlien.RNAcentralHTTP: getRNACentralEntries :: [String] -> IO [Either String RNAcentralEntryResponse]
+ Biobase.RNAlien.RNAcentralHTTP: instance Data.Aeson.Types.FromJSON.FromJSON Biobase.RNAlien.RNAcentralHTTP.RNAcentralEntry
+ Biobase.RNAlien.RNAcentralHTTP: instance Data.Aeson.Types.FromJSON.FromJSON Biobase.RNAlien.RNAcentralHTTP.RNAcentralEntryResponse
+ Biobase.RNAlien.RNAcentralHTTP: instance Data.Aeson.Types.ToJSON.ToJSON Biobase.RNAlien.RNAcentralHTTP.RNAcentralEntry
+ Biobase.RNAlien.RNAcentralHTTP: instance Data.Aeson.Types.ToJSON.ToJSON Biobase.RNAlien.RNAcentralHTTP.RNAcentralEntryResponse
+ Biobase.RNAlien.RNAcentralHTTP: instance GHC.Classes.Eq Biobase.RNAlien.RNAcentralHTTP.RNAcentralEntry
+ Biobase.RNAlien.RNAcentralHTTP: instance GHC.Classes.Eq Biobase.RNAlien.RNAcentralHTTP.RNAcentralEntryResponse
+ Biobase.RNAlien.RNAcentralHTTP: instance GHC.Generics.Generic Biobase.RNAlien.RNAcentralHTTP.RNAcentralEntry
+ Biobase.RNAlien.RNAcentralHTTP: instance GHC.Generics.Generic Biobase.RNAlien.RNAcentralHTTP.RNAcentralEntryResponse
+ Biobase.RNAlien.RNAcentralHTTP: instance GHC.Show.Show Biobase.RNAlien.RNAcentralHTTP.RNAcentralEntry
+ Biobase.RNAlien.RNAcentralHTTP: instance GHC.Show.Show Biobase.RNAlien.RNAcentralHTTP.RNAcentralEntryResponse
+ Biobase.RNAlien.RNAcentralHTTP: rnaCentralHTTP :: String -> IO (Either String RNAcentralEntryResponse)
+ Biobase.RNAlien.RNAcentralHTTP: showRNAcentralAlienEvaluation :: [Either String RNAcentralEntryResponse] -> String
+ Biobase.RNAlien.Types: CMsearch :: String -> String -> String -> [CMsearchHit] -> CMsearch
+ Biobase.RNAlien.Types: CMsearchHit :: Int -> Char -> Double -> Double -> Double -> ByteString -> Int -> Int -> Char -> ByteString -> ByteString -> Double -> ByteString -> CMsearchHit
+ Biobase.RNAlien.Types: CMstat :: Int -> String -> String -> Int -> Double -> Int -> Int -> Int -> Int -> String -> Double -> Double -> CMstat
+ Biobase.RNAlien.Types: ModelConstruction :: Int -> [Fasta () ()] -> [TaxonomyRecord] -> Maybe Int -> Maybe Taxon -> Double -> Bool -> [Fasta () ()] -> [SearchResult] -> ModelConstruction
+ Biobase.RNAlien.Types: SearchResult :: [(Fasta () (), Int, ByteString)] -> Maybe Double -> SearchResult
+ Biobase.RNAlien.Types: SequenceRecord :: Fasta () () -> Int -> ByteString -> SequenceRecord
+ Biobase.RNAlien.Types: StaticOptions :: String -> String -> Double -> Maybe Int -> Bool -> String -> Int -> Bool -> Bool -> Bool -> Int -> Maybe String -> Maybe String -> Bool -> Bool -> StaticOptions
+ Biobase.RNAlien.Types: TaxonomyRecord :: Int -> [SequenceRecord] -> TaxonomyRecord
+ Biobase.RNAlien.Types: [aligned] :: SequenceRecord -> Int
+ Biobase.RNAlien.Types: [alignmentModeInfernal] :: ModelConstruction -> Bool
+ Biobase.RNAlien.Types: [blastDatabaseSize] :: SearchResult -> Maybe Double
+ Biobase.RNAlien.Types: [blastDatabase] :: StaticOptions -> Maybe String
+ Biobase.RNAlien.Types: [blastSoftmaskingToggle] :: StaticOptions -> Bool
+ Biobase.RNAlien.Types: [candidates] :: SearchResult -> [(Fasta () (), Int, ByteString)]
+ Biobase.RNAlien.Types: [cmsearchHits] :: CMsearch -> [CMsearchHit]
+ Biobase.RNAlien.Types: [coverageFilterToggle] :: StaticOptions -> Bool
+ Biobase.RNAlien.Types: [cpuThreads] :: StaticOptions -> Int
+ Biobase.RNAlien.Types: [evalueThreshold] :: ModelConstruction -> Double
+ Biobase.RNAlien.Types: [hitBias] :: CMsearchHit -> Double
+ Biobase.RNAlien.Types: [hitDescription] :: CMsearchHit -> ByteString
+ Biobase.RNAlien.Types: [hitEnd] :: CMsearchHit -> Int
+ Biobase.RNAlien.Types: [hitEvalue] :: CMsearchHit -> Double
+ Biobase.RNAlien.Types: [hitGCContent] :: CMsearchHit -> Double
+ Biobase.RNAlien.Types: [hitModel] :: CMsearchHit -> ByteString
+ Biobase.RNAlien.Types: [hitRank] :: CMsearchHit -> Int
+ Biobase.RNAlien.Types: [hitScore] :: CMsearchHit -> Double
+ Biobase.RNAlien.Types: [hitSequenceHeader] :: CMsearchHit -> ByteString
+ Biobase.RNAlien.Types: [hitSignificance] :: CMsearchHit -> Char
+ Biobase.RNAlien.Types: [hitStart] :: CMsearchHit -> Int
+ Biobase.RNAlien.Types: [hitStrand] :: CMsearchHit -> Char
+ Biobase.RNAlien.Types: [hitTruncation] :: CMsearchHit -> ByteString
+ Biobase.RNAlien.Types: [inputFasta] :: ModelConstruction -> [Fasta () ()]
+ Biobase.RNAlien.Types: [iterationNumber] :: ModelConstruction -> Int
+ Biobase.RNAlien.Types: [lengthFilterToggle] :: StaticOptions -> Bool
+ Biobase.RNAlien.Types: [nSCICutoff] :: StaticOptions -> Double
+ Biobase.RNAlien.Types: [nucleotideSequence] :: SequenceRecord -> Fasta () ()
+ Biobase.RNAlien.Types: [numberOfWorkerThreads] :: CMsearch -> String
+ Biobase.RNAlien.Types: [offline] :: StaticOptions -> Bool
+ Biobase.RNAlien.Types: [potentialMembers] :: ModelConstruction -> [SearchResult]
+ Biobase.RNAlien.Types: [queryCMfile] :: CMsearch -> String
+ Biobase.RNAlien.Types: [queryNumber] :: StaticOptions -> Int
+ Biobase.RNAlien.Types: [querySelectionMethod] :: StaticOptions -> String
+ Biobase.RNAlien.Types: [recordDescription] :: SequenceRecord -> ByteString
+ Biobase.RNAlien.Types: [recordTaxonomyId] :: TaxonomyRecord -> Int
+ Biobase.RNAlien.Types: [relativeEntropyCM] :: CMstat -> Double
+ Biobase.RNAlien.Types: [relativeEntropyHMM] :: CMstat -> Double
+ Biobase.RNAlien.Types: [selectedQueries] :: ModelConstruction -> [Fasta () ()]
+ Biobase.RNAlien.Types: [sequenceRecords] :: TaxonomyRecord -> [SequenceRecord]
+ Biobase.RNAlien.Types: [sessionID] :: StaticOptions -> String
+ Biobase.RNAlien.Types: [singleHitperTaxToggle] :: StaticOptions -> Bool
+ Biobase.RNAlien.Types: [statAccession] :: CMstat -> String
+ Biobase.RNAlien.Types: [statBasepairs] :: CMstat -> Int
+ Biobase.RNAlien.Types: [statBifurcations] :: CMstat -> Int
+ Biobase.RNAlien.Types: [statConsensusLength] :: CMstat -> Int
+ Biobase.RNAlien.Types: [statEffectiveSequences] :: CMstat -> Double
+ Biobase.RNAlien.Types: [statIndex] :: CMstat -> Int
+ Biobase.RNAlien.Types: [statModel] :: CMstat -> String
+ Biobase.RNAlien.Types: [statName] :: CMstat -> String
+ Biobase.RNAlien.Types: [statSequenceNumber] :: CMstat -> Int
+ Biobase.RNAlien.Types: [statW] :: CMstat -> Int
+ Biobase.RNAlien.Types: [targetSequenceDatabase] :: CMsearch -> String
+ Biobase.RNAlien.Types: [taxRecords] :: ModelConstruction -> [TaxonomyRecord]
+ Biobase.RNAlien.Types: [taxRestriction] :: StaticOptions -> Maybe String
+ Biobase.RNAlien.Types: [taxonomicContext] :: ModelConstruction -> Maybe Taxon
+ Biobase.RNAlien.Types: [tempDirPath] :: StaticOptions -> String
+ Biobase.RNAlien.Types: [upperTaxonomyLimit] :: ModelConstruction -> Maybe Int
+ Biobase.RNAlien.Types: [userTaxId] :: StaticOptions -> Maybe Int
+ Biobase.RNAlien.Types: [verbositySwitch] :: StaticOptions -> Bool
+ Biobase.RNAlien.Types: data CMsearch
+ Biobase.RNAlien.Types: data CMsearchHit
+ Biobase.RNAlien.Types: data CMstat
+ Biobase.RNAlien.Types: data ModelConstruction
+ Biobase.RNAlien.Types: data SearchResult
+ Biobase.RNAlien.Types: data SequenceRecord
+ Biobase.RNAlien.Types: data StaticOptions
+ Biobase.RNAlien.Types: data TaxonomyRecord
+ Biobase.RNAlien.Types: instance GHC.Classes.Eq Biobase.RNAlien.Types.CMsearch
+ Biobase.RNAlien.Types: instance GHC.Classes.Eq Biobase.RNAlien.Types.CMsearchHit
+ Biobase.RNAlien.Types: instance GHC.Classes.Eq Biobase.RNAlien.Types.CMstat
+ Biobase.RNAlien.Types: instance GHC.Read.Read Biobase.RNAlien.Types.CMsearch
+ Biobase.RNAlien.Types: instance GHC.Read.Read Biobase.RNAlien.Types.CMsearchHit
+ Biobase.RNAlien.Types: instance GHC.Read.Read Biobase.RNAlien.Types.CMstat
+ Biobase.RNAlien.Types: instance GHC.Show.Show Biobase.RNAlien.Types.CMsearch
+ Biobase.RNAlien.Types: instance GHC.Show.Show Biobase.RNAlien.Types.CMsearchHit
+ Biobase.RNAlien.Types: instance GHC.Show.Show Biobase.RNAlien.Types.CMstat
+ Biobase.RNAlien.Types: instance GHC.Show.Show Biobase.RNAlien.Types.ModelConstruction
+ Biobase.RNAlien.Types: instance GHC.Show.Show Biobase.RNAlien.Types.SearchResult
+ Biobase.RNAlien.Types: instance GHC.Show.Show Biobase.RNAlien.Types.SequenceRecord
+ Biobase.RNAlien.Types: instance GHC.Show.Show Biobase.RNAlien.Types.StaticOptions
+ Biobase.RNAlien.Types: instance GHC.Show.Show Biobase.RNAlien.Types.TaxonomyRecord

Files

+ Biobase/RNAcentralHTTPRequest.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE DeriveDataTypeable #-}++-- | RNAcentralHTTPRequest+--   Testcommand: dist/build/RNAcentralHTTPRequest/RNAcentralHTTPRequest -i ATACTTACCTGGCACAGGGGATACCACGATCACCAAGGTGGTTCCCCCAAGACGAGGCTCACCATTGCACTCCGGTGGCGCTGACCCTTGCAATGACCCCAAATGTGGGTTACTCGGGTGTGTAATTTCTGTTAGCTGGGGACTGCGTTCGCGCTTTCCCCTT+module Main where++import System.Console.CmdArgs+import Biobase.RNAlien.RNAcentralHTTP++data Options = Options+  { inputSequence :: String+  } deriving (Show,Data,Typeable)++options :: Options+options = Options+  { inputSequence = def &= name "i" &= help "input sequence"+  } &= summary "RNAcentralHTTPRequest" &= help "Florian Eggenhofer 2016" &= verbosity++main :: IO ()+main = do+  Options{..} <- cmdArgs options+  let query = buildStringViaMD5Query inputSequence+  rnacentralentries <- getRNACentralEntries [query]+  print rnacentralentries+
+ Biobase/RNAlien.hs view
@@ -0,0 +1,131 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE DeriveDataTypeable #-}++-- | Unsupervized construction of RNA family models+--   For more information on RNA family models consult <http://>+--   Usage example: RNAlien -i /path/input.fa -c 5 -o /outdir/+--   Usage example offline mode: RNAlien -i /path/input.fa -b /backup/blast/nt_v5 -o /outdir/ -c 5 -t 1396 -j +module Main where++import System.Console.CmdArgs+import System.Directory+import Biobase.RNAlien.Types+import Biobase.RNAlien.Library+import Data.Maybe+import Data.Either.Unwrap+import Data.Time+import qualified System.FilePath as FP+import Paths_RNAlien (version)+import Data.Version (showVersion)+--import Biobase.Fasta.Streaming++data Options = Options+  { inputFastaFilePath :: String,+    outputPath :: String,+    inputTaxId :: Maybe Int,+    inputnSCICutoff :: Maybe Double,+    inputEvalueCutoff :: Maybe Double,+    inputBlastDatabase :: Maybe String,+    lengthFilter :: Bool,+    coverageFilter :: Bool,+    singleHitperTax :: Bool,+    blastSoftmasking :: Bool,+    inputQuerySelectionMethod :: String,+    inputQueryNumber :: Int,+    threads :: Int,+    taxonomyRestriction :: Maybe String,+    sessionIdentificator :: Maybe String,+    performEvaluation :: Bool,+    checkSetup :: Bool,+    offlineMode :: Bool+  } deriving (Show,Data,Typeable)++options :: Options+options = Options+  { inputFastaFilePath = def &= name "i" &= help "Path to input fasta file",+    outputPath = def &= name "o" &= help "Path to output directory. Default: current working directory",+    inputTaxId = Nothing &= name "t" &= help "NCBI taxonomy ID number of input RNA organism",+    inputnSCICutoff = Just (1 :: Double) &= name "z" &= help "Only candidate sequences with a normalized structure conservation index (nSCI) higher than this value are accepted. Default: 1",+    inputEvalueCutoff = Just (0.001 :: Double) &= name "e" &= help "Evalue cutoff for cmsearch filtering. Default: 0.001",+    inputBlastDatabase = Just "nt" &= name "b" &= help "Specify name of blast database to use, in offline mode the filepath to the blast database (/home/user/nt_v5). Default: nt",+    lengthFilter = True &= name "l" &= help "Filter blast hits per genomic length. Default: True",+    coverageFilter = True &= name "a" &= help "Filter blast hits by coverage of at least 80%. Default: True",+    singleHitperTax = False &= name "s" &= help "Only the best blast hit per taxonomic entry is considered. Default: False",+    blastSoftmasking = False &= name "f" &= help "Toggles blast query softmasking, meaning masking of non-conserved regions on the query. Default: False",+    inputQuerySelectionMethod = "filtering" &= name "m" &= help "Method for selection of queries (filtering,clustering). Default: filtering",+    inputQueryNumber = (5 :: Int) &= name "n" &= help "Number of queries used for candidate search. Default: 5",+    threads = 1 &= name "c" &= help "Number of available cpu slots/cores. Default: 1",+    taxonomyRestriction = Nothing &= name "r" &= help "Restrict search space to taxonomic kingdom (bacteria,archea,eukaryia). Default: not set",+    sessionIdentificator = Nothing &= name "d" &= help "Optional session id that is used instead of automatically generated one.",+    performEvaluation = True &= name "x" &= help "Perform evaluation step. Default: True",+    checkSetup = False &= name "g" &= help "Just prints installed tool versions and performs connection check. Default: False",+    offlineMode = False &= name "j" &= help "Uses locally installed blast and databases. Default: False"+  } &= summary ("RNAlien " ++ alienVersion) &= help "Florian Eggenhofer, Ivo L. Hofacker, Christian Hoener zu Siederdissen - 2013 - 2019" &= verbosity++main :: IO ()+main = do+  Options{..} <- cmdArgs options+  verboseLevel <- getVerbosity+  let tools = if inputQuerySelectionMethod == "clustering" then ["clustalo","mlocarna","RNAfold","RNAalifold","cmcalibrate","cmstat","cmbuild","RNAz","RNAcode"] else ["mlocarna","RNAfold","RNAalifold","cmcalibrate","cmstat","cmbuild","RNAz","RNAcode"]+  -- Generate SessionID+  sessionId <- createSessionID sessionIdentificator+  timestamp <- getCurrentTime+  currentWorkDirectory <- getCurrentDirectory+  let selectedOutputPath = if null outputPath then currentWorkDirectory else outputPath+  let temporaryDirectoryPath = FP.addTrailingPathSeparator selectedOutputPath ++ sessionId ++ "/"+  createDirectoryIfMissing False temporaryDirectoryPath+  networkCheck <- checkNCBIConnection+  if checkSetup+    then do+      toolsCheck <- checkTools tools inputQuerySelectionMethod temporaryDirectoryPath+      let setupCheckPath = temporaryDirectoryPath ++ "setupCheck"+      let toolCheckResult = either id id toolsCheck+      let networkCheckResult = either id id networkCheck+      writeFile setupCheckPath (toolCheckResult ++ "\n" ++ networkCheckResult ++ "\n")+    else+      if isLeft networkCheck+        then do+          putStrLn ("Error - Could not contact NCBI server: " ++ fromLeft networkCheck ++ "\n")+          logMessage ("Error - Could not contact NCBI server: " ++ fromLeft networkCheck ++ "\n") temporaryDirectoryPath+       else do+           createDirectoryIfMissing False (temporaryDirectoryPath ++ "log")+           -- Create Log files+           writeFile (temporaryDirectoryPath ++ "Log") ("RNAlien " ++ alienVersion ++ "\n")+           writeFile (temporaryDirectoryPath ++ "log/warnings") ("")+           logMessage ("Timestamp: " ++ (show timestamp) ++ "\n") temporaryDirectoryPath+           logMessage ("Temporary Directory: " ++ temporaryDirectoryPath ++ "\n") temporaryDirectoryPath+           inputFasta <- readFastaFile inputFastaFilePath+           if null inputFasta+             then do+               putStrLn "Error: Input fasta file is empty."+               logMessage "Error: Input fasta file is empty.\n" temporaryDirectoryPath+             else do+               let iterationNumber = 0+               toolsCheck <- checkTools tools inputQuerySelectionMethod temporaryDirectoryPath+               if isLeft toolsCheck+                 then do+                   putStrLn ("Error - Not all required tools could be found in $PATH: " ++ fromLeft toolsCheck ++ "\n")+                   logMessage ("Error - Not all required tools could be found in $PATH: " ++ fromLeft toolsCheck ++ "\n") temporaryDirectoryPath+                 else do+                   logToolVersions inputQuerySelectionMethod temporaryDirectoryPath+                   let inputSequence = reformatFasta (head inputFasta)+                   initialTaxId <- setInitialTaxId offlineMode threads inputBlastDatabase temporaryDirectoryPath inputTaxId inputSequence+                   let checkedTaxonomyRestriction = checkTaxonomyRestriction taxonomyRestriction+                   let staticOptions = StaticOptions temporaryDirectoryPath sessionId (fromJust inputnSCICutoff) inputTaxId singleHitperTax inputQuerySelectionMethod inputQueryNumber lengthFilter coverageFilter blastSoftmasking threads inputBlastDatabase checkedTaxonomyRestriction (setVerbose verboseLevel) offlineMode+                   let initialization = ModelConstruction iterationNumber inputFasta [] initialTaxId Nothing (fromJust inputEvalueCutoff) False [] []+                   logMessage (show initialization) temporaryDirectoryPath+                   modelConstructionResults <- modelConstructer staticOptions initialization+                   let resultTaxonomyRecordsCSVTable = constructTaxonomyRecordsCSVTable modelConstructionResults+                   writeFile (temporaryDirectoryPath ++ "result.csv") resultTaxonomyRecordsCSVTable+                   if performEvaluation+                     then do+                       resultEvaluation <- evaluateConstructionResult staticOptions modelConstructionResults+                       appendFile (temporaryDirectoryPath ++ "Log") resultEvaluation+                       resultSummary modelConstructionResults staticOptions+                       writeFile (temporaryDirectoryPath ++ "done") ""+                     else do+                       resultSummary modelConstructionResults staticOptions+                       writeFile (temporaryDirectoryPath ++ "done") ""++alienVersion :: String+alienVersion = showVersion version
+ Biobase/RNAlien/InfernalParser.hs view
@@ -0,0 +1,340 @@+-- | This module contains parsing functions for Infernal programs++module Biobase.RNAlien.InfernalParser (+                           module Biobase.RNAlien.Types,+                           readCMSearch,+                           readCMSearches,+                           parseCMSearch,+                           parseCMSearches,+                           parseCMstat,+                           readCMstat+                           )+where++import Text.ParserCombinators.Parsec+import Biobase.RNAlien.Types+import qualified Data.ByteString.Char8 as B+import qualified Control.Exception.Base as CE++-- | parse from input filePath              +parseCMSearch :: String -> Either ParseError CMsearch+parseCMSearch = parse genParserCMSearch "parseCMsearch"++-- | parse from input filePath              +parseCMSearches :: String -> Either ParseError CMsearch+parseCMSearches = parse genParserCMSearches "parseCMsearch"++-- | parse from input filePath                      +readCMSearch :: String -> IO (Either ParseError CMsearch)+readCMSearch filePath = do+  parsedFile <- parseFromFile genParserCMSearch filePath+  CE.evaluate parsedFile++-- | parse from input filePath                      +readCMSearches :: String -> IO (Either ParseError CMsearch)+readCMSearches filePath = do+  parsedFile <- parseFromFile genParserCMSearches filePath+  CE.evaluate parsedFile++genParserCMSearches :: GenParser Char st CMsearch+genParserCMSearches = do+  string "# cmsearch :: search CM(s) against a sequence database"+  newline+  string "# INFERNAL "+  many1 (noneOf "\n")+  newline+  string "# Copyright (C) 201"+  many1 (noneOf "\n")+  newline+  string "# Freely distributed under the GNU General Public License (GPLv3)."+  newline+  string "# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"+  newline+  string "# query CM file:"+  many1 space+  queryCMfile' <- many1 (noneOf "\n")+  newline+  string "# target sequence database:"+  many1 space+  targetSequenceDatabase' <- many1 (noneOf "\n")+  newline+  optional (try (genParserCMsearchHeaderField "# CM configuration"))+  optional (try (genParserCMsearchHeaderField "# database size is set to"))+  optional (try (genParserCMsearchHeaderField "# truncated sequence detection"))+  string "# number of worker threads:"+  many1 space+  numberOfWorkerThreads' <- many1 (noneOf "\n")+  newline+  string "# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"+  newline+  optional newline+  cmSearchesHits <- many1 (try genParserMultipleCMSearch)+  optional (string "[ok]\n")+  eof+  return $ CMsearch queryCMfile' targetSequenceDatabase' numberOfWorkerThreads' (concat cmSearchesHits)++genParserCMSearch :: GenParser Char st CMsearch+genParserCMSearch = do+  string "# cmsearch :: search CM(s) against a sequence database"+  newline+  string "# INFERNAL "+  many1 (noneOf "\n")+  newline+  string "# Copyright (C) 201"+  many1 (noneOf "\n")+  newline+  string "# Freely distributed under the GNU General Public License (GPLv3)."+  newline+  string "# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"+  newline+  string "# query CM file:"+  many1 space+  queryCMfile' <- many1 (noneOf "\n")+  newline+  string "# target sequence database:"+  many1 space+  targetSequenceDatabase' <- many1 (noneOf "\n")+  newline+  optional (try (genParserCMsearchHeaderField "# CM configuration"))+  optional (try (genParserCMsearchHeaderField "# database size is set to"))+  optional (try (genParserCMsearchHeaderField "# truncated sequence detection"))+  string "# number of worker threads:"+  many1 space+  numberOfWorkerThreads' <- many1 (noneOf "\n")+  newline+  string "# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"+  newline+  optional newline+  string "Query:"+  many1 (noneOf "\n")+  newline+  optional (try (genParserCMsearchHeaderField "Accession"))+  optional (try (genParserCMsearchHeaderField "Description"))+  string "Hit scores:"+  newline+  choice  [try (string " rank"), try (string "  rank") , try (string "   rank"), try (string "    rank"),try (string "     rank"),try (string "      rank")]+  many1 space+  string "E-value"+  many1 space+  string "score"+  many1 space+  string "bias"+  many1 space+  string "sequence"+  many1 space+  string "start"+  many1 space+  string "end"+  many1 space+  string "mdl"+  many1 space+  string "trunc"+  many1 space+  string "gc"+  many1 space+  string "description"+  newline+  string " -"+  many1 (try (oneOf " -"))+  newline+  optional (try (string " ------ inclusion threshold ------"))+  many newline+  hitScores' <- many (try genParserCMsearchHit) --`endBy` (try (string "Hit alignments:"))+  optional (try genParserCMsearchEmptyHit)+  -- this is followed by hit alignments and internal cmsearch statistics which are not parsed+  many anyChar+  eof+  return $ CMsearch queryCMfile' targetSequenceDatabase' numberOfWorkerThreads' hitScores'++-- | Parsing function for CMSearches with multiple querymodels in one modelfile, e.g. clans+genParserMultipleCMSearch :: GenParser Char st [CMsearchHit]+genParserMultipleCMSearch = do+  --optional newline+  --optional string "//"+  string "Query:"+  many1 (noneOf "\n")+  newline+  optional (try (genParserCMsearchHeaderField "Accession"))+  optional (try (genParserCMsearchHeaderField "Description"))+  string "Hit scores:"+  newline+  choice  [try (string " rank"), try (string "  rank") , try (string "   rank"), try (string "    rank"),try (string "     rank"),try (string "      rank")]+  many1 space+  string "E-value"+  many1 space+  string "score"+  many1 space+  string "bias"+  many1 space+  string "sequence"+  many1 space+  string "start"+  many1 space+  string "end"+  many1 space+  string "mdl"+  many1 space+  string "trunc"+  many1 space+  string "gc"+  many1 space+  string "description"+  newline+  string " -"+  many1 (try (oneOf " -"))+  newline+  optional (try (string " ------ inclusion threshold ------"))+  many newline+  hitScores' <- many (try genParserCMsearchHit) --`endBy` (try (string "Hit alignments:"))+  optional (try genParserCMsearchEmptyHit)+  -- this is followed by hit alignments and internal cmsearch statistics which are not parsed+  --many anyChar+  manyTill anyChar (try (string "//\n"))+  return hitScores'++genParserCMsearchHeaderField :: String -> GenParser Char st String+genParserCMsearchHeaderField fieldname = do+  string (fieldname ++ ":")+  many1 space+  many1 (noneOf "\n")+  newline+  return []++genParserCMsearchEmptyHit :: GenParser Char st [CMsearchHit]+genParserCMsearchEmptyHit = do+  string "   [No hits detected that satisfy reporting thresholds]"+  newline+  optional (try newline)+  return []++genParserCMsearchHit :: GenParser Char st CMsearchHit+genParserCMsearchHit = do+  many1 space+  string "("+  hitRank' <- many1 digit+  string ")"+  many1 space+  hitSignificant' <- choice [char '!', char '?']+  many1 space+  hitEValue' <- many1 (oneOf "0123456789.e-")+  many1 space+  hitScore'  <- many1 (oneOf "0123456789.e-")+  many1 space+  hitBias' <- many1 (oneOf "0123456789.e-")+  many1 space+  hitSequenceHeader' <- many1 (noneOf " ")+  many1 space+  hitStart' <- many1 digit+  many1 space+  hitEnd' <- many1 digit+  many1 space+  hitStrand' <- choice [char '+', char '-', char '.']+  many1 space+  hitModel' <- many1 letter+  many1 space+  hitTruncation' <- many1 (choice [alphaNum, char '\''])+  many1 space+  hitGCcontent' <- many1 (oneOf "0123456789.e-")+  many1 space+  hitDescription' <- many1 (noneOf "\n")+  newline+  optional (try (string " ------ inclusion threshold ------"))+  optional (try newline)+  return $ CMsearchHit (readInt hitRank') hitSignificant' (readDouble hitEValue') (readDouble hitScore') (readDouble hitBias') (B.pack hitSequenceHeader') (readInt hitStart') (readInt hitEnd') hitStrand' (B.pack hitModel') (B.pack hitTruncation') (readDouble hitGCcontent') (B.pack hitDescription')++-- | parse from input filePath              +parseCMstat :: String -> Either ParseError CMstat+parseCMstat = parse genParserCMstat "parseCMstat"++-- | parse from input filePath                      +readCMstat :: String -> IO (Either ParseError CMstat)+readCMstat filePath = do+  parsedFile <- parseFromFile genParserCMstat filePath+  CE.evaluate parsedFile++genParserCMstat :: GenParser Char st CMstat+genParserCMstat = do+  string "# cmstat :: display summary statistics for CMs"+  newline+  string "# INFERNAL "+  many1 (noneOf "\n")+  newline+  string "# Copyright (C) 201"+  many1 (noneOf "\n")+  newline+  string "# Freely distributed under the GNU General Public License (GPLv3)."+  newline+  string "# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"+  newline+  char '#'+  many1 (char ' ')+  string "rel entropy"+  newline+  char '#'+  many1 (char ' ')+  many1 (char '-')+  newline+  char '#'+  many1 space+  string "idx"+  many1 space+  string "name"+  many1 space+  string "accession"+  many1 space+  string "nseq"+  many1 space+  string "eff_nseq"+  many1 space+  string "clen"+  many1 space+  string "W"+  many1 space+  string "bps"+  many1 space+  string "bifs"+  many1 space+  string "model"+  many1 space+  string "cm"+  many1 space+  string "hmm"+  newline+  string "#"+  many1 (try (oneOf " -"))+  newline+  many1 space+  _statIndex <- many1 digit+  many1 space+  _statName <- many1 letter+  many1 space+  _statAccession <- many1 (noneOf " ")+  many1 space+  _statSequenceNumber <- many1 digit+  many1 space+  _statEffectiveSequences <- many1 (oneOf "0123456789.e-")+  many1 space+  _statConsensusLength <- many digit+  many1 space+  _statW <- many1 digit+  many1 space+  _statBasepaires <- many1 digit+  many1 space+  _statBifurcations <- many1 digit+  many1 space+  _statModel <- many1 letter+  many1 space+  _relativeEntropyCM <- many1 (oneOf "0123456789.e-")+  many1 space+  _relativeEntropyHMM <- many1 (oneOf "0123456789.e-")+  newline+  char '#'+  newline+  eof+  return $ CMstat (readInt _statIndex) _statName _statAccession (readInt _statSequenceNumber) (readDouble _statEffectiveSequences) (readInt _statConsensusLength) (readInt _statW) (readInt _statBasepaires) (readInt _statBifurcations) _statModel (readDouble _relativeEntropyCM) (readDouble _relativeEntropyHMM)+--   +readInt :: String -> Int+readInt = read++readDouble :: String -> Double+readDouble = read
+ Biobase/RNAlien/Library.hs view
@@ -0,0 +1,2032 @@+-- | This module contains functions for RNAlien+{-# LANGUAGE RankNTypes #-}+module Biobase.RNAlien.Library (+                           module Biobase.RNAlien.Types,+                           createSessionID,+                           logMessage,+                           logEither,+                           modelConstructer,+                           constructTaxonomyRecordsCSVTable,+                           resultSummary,+                           setVerbose,+                           logToolVersions,+                           checkTools,+                           systemCMsearch,+                           readCMSearch,+                           readCMSearches,+                           compareCM,+                           parseCMSearch,+                           cmSearchsubString,+                           setInitialTaxId,+                           evaluateConstructionResult,+                           readCMstat,+                           parseCMstat,+                           checkNCBIConnection,+                           preprocessClustalForRNAz,+                           preprocessClustalForRNAzExternal,+                           preprocessClustalForRNAcodeExternal,+                           rnaZEvalOutput,+                           reformatFasta,+                           checkTaxonomyRestriction,+                           evaluePartitionTrimCMsearchHits,+                           readFastaFile,+                           writeFastaFile          +                           )+where++import System.Process+import qualified System.FilePath as FP+import Text.ParserCombinators.Parsec+import Data.List+import Data.Char+import Biobase.Fasta.Strict+import qualified Biobase.BLAST.Types as J+import Bio.ClustalParser+import Data.Int (Int16)+import Biobase.RNAlien.Types+import qualified Data.ByteString.Lazy.Char8 as L+import qualified Data.ByteString.Char8 as B+import Bio.Taxonomy+import Data.Either.Unwrap+import Data.Maybe+import Biobase.Entrez.HTTP+import System.Exit+import Data.Either (lefts,rights,Either)+import qualified Text.EditDistance as ED+import qualified Data.Vector as V+import Control.Concurrent+import System.Random+import Data.Csv+import Data.Matrix+import Biobase.BLAST.HTTP+import Data.Clustering.Hierarchical+import System.Directory+import System.Console.CmdArgs+import qualified Control.Exception.Base as CE+import Bio.RNAfoldParser+import Bio.RNAalifoldParser+import Bio.RNAzParser+import qualified Network.HTTP.Conduit as N+import Network.HTTP.Types.Status+import qualified Bio.RNAcodeParser as RC+import qualified Biobase.RNAlien.RNAcentralHTTP as RCH+import Biobase.RNAlien.InfernalParser+import qualified Data.Text as T+import qualified Data.Text.IO as TI+import qualified Data.Text.Encoding as E+import qualified Data.Text.Lazy as TL+import qualified Data.Text.Lazy.IO as TIO+import Text.Printf+import qualified Data.Text.Metrics as TM+import Control.Monad+import qualified Data.Sequence as DS+import Data.Foldable+import Biobase.Types.BioSequence+import qualified Biobase.BLAST.Import as BBI++-- | Initial RNA family model construction - generates iteration number, seed alignment and model+modelConstructer :: StaticOptions -> ModelConstruction -> IO ModelConstruction+modelConstructer staticOptions modelConstruction = do+  logMessage ("Iteration: " ++ show (iterationNumber modelConstruction) ++ "\n") (tempDirPath staticOptions)+  iterationSummary modelConstruction staticOptions+  let currentIterationNumber = iterationNumber modelConstruction+  let foundSequenceNumber = length (concatMap sequenceRecords (taxRecords modelConstruction))+  --extract queries+  let queries = extractQueries foundSequenceNumber modelConstruction+  logVerboseMessage (verbositySwitch staticOptions) ("Queries:" ++ show queries ++ "\n") (tempDirPath staticOptions)+  let iterationDirectory = tempDirPath staticOptions ++ show currentIterationNumber ++ "/"+  let maybeLastTaxId = extractLastTaxId (taxonomicContext modelConstruction)+  Control.Monad.when (isNothing maybeLastTaxId) $ logMessage ("Lineage: Could not extract last tax id \n") (tempDirPath staticOptions)+  --If highest node in linage was used as upper taxonomy limit, taxonomic tree is exhausted+  if maybe True (\uppertaxlimit -> maybe True (\lastTaxId -> uppertaxlimit /= lastTaxId) maybeLastTaxId) (upperTaxonomyLimit modelConstruction)+     then do+       createDirectory iterationDirectory+       let (upperTaxLimit,lowerTaxLimit) = setTaxonomicContextEntrez currentIterationNumber (taxonomicContext modelConstruction) (upperTaxonomyLimit modelConstruction)+       logVerboseMessage (verbositySwitch staticOptions) ("Upper taxonomy limit: " ++ show upperTaxLimit ++ "\n " ++ "Lower taxonomy limit: "++ show lowerTaxLimit ++ "\n") (tempDirPath staticOptions)+       --search queries+       let expectThreshold = setBlastExpectThreshold modelConstruction+       searchResults <- catchAll (searchCandidates staticOptions Nothing currentIterationNumber upperTaxLimit lowerTaxLimit expectThreshold queries)+                        (\e -> do logWarning ("Warning: Search results iteration" ++ show (iterationNumber modelConstruction) ++ " - exception: " ++ show e) (tempDirPath staticOptions)+                                  return (SearchResult [] Nothing))+       currentTaxonomicContext <- getTaxonomicContextEntrez upperTaxLimit (taxonomicContext modelConstruction)+       if null (candidates searchResults)+         then+            alignmentConstructionWithoutCandidates currentTaxonomicContext upperTaxLimit staticOptions modelConstruction+         else+            alignmentConstructionWithCandidates currentTaxonomicContext upperTaxLimit searchResults staticOptions modelConstruction+     else do+       logMessage "Message: Modelconstruction complete: Out of queries or taxonomic tree exhausted\n" (tempDirPath staticOptions)+       modelConstructionResult staticOptions modelConstruction++catchAll :: IO a -> (CE.SomeException -> IO a) -> IO a+catchAll = CE.catch++setInitialTaxId :: Bool -> Int -> Maybe String -> String -> Maybe Int -> Fasta () ()-> IO (Maybe Int)+setInitialTaxId offlineMode threads inputBlastDatabase tempdir inputTaxId inputSequence =+  if (isNothing inputTaxId)+    then do+      initialTaxId <- findTaxonomyStart offlineMode threads inputBlastDatabase tempdir inputSequence+      return (Just initialTaxId)+    else do+        return inputTaxId++extractLastTaxId :: Maybe Taxon -> Maybe Int+extractLastTaxId taxon+  | isNothing taxon = Nothing+  | V.null lineageExVector = Nothing+  | otherwise = Just (lineageTaxId (V.head lineageExVector))+    where lineageExVector = V.fromList (lineageEx (fromJust taxon))++modelConstructionResult :: StaticOptions -> ModelConstruction -> IO ModelConstruction+modelConstructionResult staticOptions modelConstruction = do+  let currentIterationNumber = iterationNumber modelConstruction+  let outputDirectory = tempDirPath staticOptions+  logMessage ("Global search iteration: " ++ show currentIterationNumber ++ "\n") outputDirectory+  iterationSummary modelConstruction staticOptions+  let foundSequenceNumber = length (concatMap sequenceRecords (taxRecords modelConstruction))+  --extract queries+  --let querySeqIds = selectedQueries modelConstruction ---+  let queries = extractQueries foundSequenceNumber modelConstruction ---+  --let alignedSequences' = map nucleotideSequence (concatMap sequenceRecords (taxRecords modelConstruction)) ---+  logVerboseMessage (verbositySwitch staticOptions) ("Queries:" ++ show queries ++ "\n") outputDirectory+  let iterationDirectory = outputDirectory ++ show currentIterationNumber ++ "/"+  createDirectory iterationDirectory+  let logFileDirectoryPath = iterationDirectory ++ "log"+  createDirectoryIfMissing False logFileDirectoryPath+  let expectThreshold = setBlastExpectThreshold modelConstruction+  (alignmentResults,currentPotentialMembers) <- if isJust (taxRestriction staticOptions)+    then do+      --taxonomic restriction+      let (upperTaxLimit,lowerTaxLimit) = setRestrictedTaxonomyLimits (fromJust (taxRestriction staticOptions))+      restrictedCandidates <- catchAll (searchCandidates staticOptions (taxRestriction staticOptions) currentIterationNumber upperTaxLimit lowerTaxLimit expectThreshold queries)+                     (\e -> do logWarning ("Warning: Search results iteration" ++ show currentIterationNumber ++ " - exception: " ++ show e) outputDirectory+                               return (SearchResult [] Nothing))+      let uniqueCandidates = filterDuplicates modelConstruction restrictedCandidates+      (restrictedAlignmentResults,restrictedPotentialMembers) <- catchAll (alignCandidates staticOptions modelConstruction (fromJust (taxRestriction staticOptions)) uniqueCandidates)+                           (\e -> do logWarning ("Warning: Alignment results iteration" ++ show currentIterationNumber ++ " - exception: " ++ show e) outputDirectory+                                     return  ([],[]))+      let currentPotentialMembers = [SearchResult restrictedPotentialMembers (blastDatabaseSize restrictedCandidates)]+      return (restrictedAlignmentResults,currentPotentialMembers)+    else do+      --taxonomic context archea+      let (upperTaxLimit1,lowerTaxLimit1) = (Just (2157 :: Int), Nothing)+      candidates1 <- catchAll  (searchCandidates staticOptions (Just "archea") currentIterationNumber upperTaxLimit1 lowerTaxLimit1 expectThreshold queries)+                     (\e -> do logWarning ("Warning: Search results iteration" ++ show currentIterationNumber ++ " - exception: " ++ show e) outputDirectory+                               return (SearchResult [] Nothing))+      let uniqueCandidates1 = filterDuplicates modelConstruction candidates1+      (alignmentResults1,potentialMembers1) <- catchAll (alignCandidates staticOptions modelConstruction "archea" uniqueCandidates1)+                           (\e -> do logWarning ("Warning: Alignment results iteration" ++ show currentIterationNumber ++ " - exception: " ++ show e) outputDirectory+                                     return  ([],[]))+      --taxonomic context bacteria+      let (upperTaxLimit2,lowerTaxLimit2) = (Just (2 :: Int), Nothing)+      candidates2 <- catchAll (searchCandidates staticOptions (Just "bacteria") currentIterationNumber upperTaxLimit2 lowerTaxLimit2 expectThreshold queries)+                     (\e -> do logWarning ("Warning: Search results iteration" ++ show currentIterationNumber ++ " - exception: " ++ show e) outputDirectory+                               return (SearchResult [] Nothing))+      let uniqueCandidates2 = filterDuplicates modelConstruction candidates2+      (alignmentResults2,potentialMembers2) <- catchAll (alignCandidates staticOptions modelConstruction "bacteria" uniqueCandidates2)+                           (\e -> do logWarning ("Warning: Alignment results iteration" ++ show currentIterationNumber ++ " - exception: " ++ show e) outputDirectory+                                     return  ([],[]))+      --taxonomic context eukaryia+      let (upperTaxLimit3,lowerTaxLimit3) = (Just (2759 :: Int), Nothing)+      candidates3 <- catchAll (searchCandidates staticOptions (Just "eukaryia") currentIterationNumber upperTaxLimit3 lowerTaxLimit3 expectThreshold queries)+                     (\e -> do logWarning ("Warning: Search results iteration" ++ show currentIterationNumber ++ " - exception: " ++ show e) outputDirectory+                               return (SearchResult [] Nothing))+      let uniqueCandidates3 = filterDuplicates modelConstruction candidates3+      (alignmentResults3,potentialMembers3) <- catchAll (alignCandidates staticOptions modelConstruction "eukaryia" uniqueCandidates3)+                           (\e -> do logWarning ("Warning: Alignment results iteration" ++ show currentIterationNumber ++ " - exception: " ++ show e) outputDirectory+                                     return  ([],[]))+      let alignmentResults = alignmentResults1 ++ alignmentResults2 ++ alignmentResults3+      let currentPotentialMembers = [SearchResult potentialMembers1 (blastDatabaseSize candidates1), SearchResult potentialMembers2 (blastDatabaseSize candidates2), SearchResult potentialMembers3 (blastDatabaseSize candidates3)]+      return (alignmentResults,currentPotentialMembers)+  let preliminaryFastaPath = iterationDirectory ++ "model.fa"+  let preliminaryCMPath = iterationDirectory ++ "model.cm"+  let preliminaryAlignmentPath = iterationDirectory ++ "model.stockholm"+  let preliminaryCMLogPath = iterationDirectory ++ "model.cm.log"+  let nextModelConstructionInput = constructNext currentIterationNumber modelConstruction alignmentResults Nothing Nothing [] currentPotentialMembers (alignmentModeInfernal modelConstruction)+  if (null alignmentResults) && not (alignmentModeInfernal modelConstruction)+    then do+      logVerboseMessage (verbositySwitch staticOptions) "Alignment result initial mode\n" outputDirectory+      logMessage "Message: No sequences found that statisfy filters. Try to reconstruct model with less strict cutoff parameters." outputDirectory+      let alignedSequences = extractAlignedSequences (iterationNumber modelConstruction) modelConstruction+      let alignmentSequences = map snd (V.toList (V.concat [alignedSequences]))+      writeFastaFile preliminaryFastaPath alignmentSequences+      let cmBuildFilepath = iterationDirectory ++ "model" ++ ".cmbuild"+      let refinedAlignmentFilepath = iterationDirectory ++ "modelrefined" ++ ".stockholm"+      let cmBuildOptions ="--refine " ++ refinedAlignmentFilepath+      let foldFilepath = iterationDirectory ++ "model" ++ ".fold"+      _ <- systemRNAfold preliminaryFastaPath foldFilepath+      foldoutput <- readRNAfold foldFilepath+      let seqStructure = foldSecondaryStructure (fromRight foldoutput)+      let stockholAlignment = convertFastaFoldStockholm (head alignmentSequences) seqStructure+      writeFile preliminaryAlignmentPath stockholAlignment+      _ <- systemCMbuild cmBuildOptions preliminaryAlignmentPath preliminaryCMPath cmBuildFilepath+      _ <- systemCMcalibrate "fast" (cpuThreads staticOptions) preliminaryCMPath preliminaryCMLogPath+      reevaluatePotentialMembers staticOptions nextModelConstructionInput+    else+      if (alignmentModeInfernal modelConstruction)+        then do+          logVerboseMessage (verbositySwitch staticOptions) ("Alignment construction with candidates - infernal mode\n") outputDirectory+          constructModel nextModelConstructionInput staticOptions+          writeFile (iterationDirectory ++ "done") ""+          logMessage (iterationSummaryLog nextModelConstructionInput) outputDirectory+          logVerboseMessage (verbositySwitch staticOptions) (show nextModelConstructionInput) outputDirectory+          resultModelConstruction <- reevaluatePotentialMembers staticOptions nextModelConstructionInput+          return resultModelConstruction+        else do+          logVerboseMessage (verbositySwitch staticOptions) ("Alignment construction with candidates - initial mode\n") outputDirectory+          constructModel nextModelConstructionInput staticOptions+          let nextModelConstructionInputInfernalMode = nextModelConstructionInput {alignmentModeInfernal = True}+          logMessage (iterationSummaryLog nextModelConstructionInputInfernalMode) outputDirectory+          logVerboseMessage (verbositySwitch staticOptions) (show nextModelConstructionInputInfernalMode) outputDirectory+          writeFile (iterationDirectory ++ "done") ""+          resultModelConstruction <- reevaluatePotentialMembers staticOptions nextModelConstructionInputInfernalMode+          return resultModelConstruction++writeFastaFile :: String -> [Fasta () ()] -> IO ()+writeFastaFile fastaFilePath alignmentSequences = do+  let sequenceOutput = B.concat (map (fastaToByteString 80) alignmentSequences)+  B.writeFile fastaFilePath sequenceOutput+                 +-- | Reevaluate collected potential members for inclusion in the result model+reevaluatePotentialMembers :: StaticOptions -> ModelConstruction -> IO ModelConstruction+reevaluatePotentialMembers staticOptions modelConstruction = do+  let currentIterationNumber = iterationNumber modelConstruction+  let outputDirectory = tempDirPath staticOptions+  iterationSummary modelConstruction staticOptions+  logMessage ("Reevaluation of potential members iteration: " ++ show currentIterationNumber ++ "\n") outputDirectory+  let iterationDirectory = outputDirectory ++ show currentIterationNumber ++ "/"+  createDirectory iterationDirectory+  let indexedPotentialMembers = V.indexed (V.fromList (potentialMembers modelConstruction))+  potentialMembersAlignmentResultVector <- V.mapM (\(i,searchresult) -> (alignCandidates staticOptions modelConstruction (show i ++ "_") searchresult)) indexedPotentialMembers+  let potentialMembersAlignmentResults = V.toList potentialMembersAlignmentResultVector+  let alignmentResults = concatMap fst potentialMembersAlignmentResults+  let discardedMembers = concatMap snd potentialMembersAlignmentResults+  writeFile (outputDirectory  ++ "log/discarded") (concatMap show discardedMembers)+  let resultFastaPath = outputDirectory  ++ "result.fa"+  let resultCMPath = outputDirectory ++ "result.cm"+  let resultAlignmentPath = outputDirectory ++ "result.stockholm"+  let resultClustalFilepath = outputDirectory ++ "result.clustal"+  let resultCMLogPath = outputDirectory ++ "log/result.cm.log"+  if null alignmentResults+    then do+      let lastIterationFastaPath = outputDirectory ++ show (currentIterationNumber - 1)++ "/model.fa"+      let lastIterationAlignmentPath = outputDirectory ++ show (currentIterationNumber - 1)  ++ "/model.stockholm"+      let lastIterationCMPath = outputDirectory ++ show (currentIterationNumber - 1)++ "/model.cm"+      copyFile lastIterationCMPath resultCMPath+      --copyFile lastIterationCMPath (resultCMPath ++ ".bak1")+      copyFile lastIterationFastaPath resultFastaPath+      copyFile lastIterationAlignmentPath resultAlignmentPath+      _ <- systemCMcalibrate "standard" (cpuThreads staticOptions) resultCMPath resultCMLogPath+      systemCMalign ("--outformat=Clustal --cpu " ++ show (cpuThreads staticOptions)) resultCMPath resultFastaPath resultClustalFilepath+      writeFile (iterationDirectory ++ "done") ""+      return modelConstruction+    else do+      let lastIterationFastaPath = outputDirectory ++ show currentIterationNumber ++ "/model.fa"+      let lastIterationAlignmentPath = outputDirectory ++ show currentIterationNumber  ++ "/model.stockholm"+      let lastIterationCMPath = outputDirectory ++ show currentIterationNumber ++ "/model.cm"+      logVerboseMessage (verbositySwitch staticOptions) "Alignment construction with candidates - infernal mode\n" outputDirectory+      let nextModelConstructionInput = constructNext currentIterationNumber modelConstruction alignmentResults Nothing Nothing [] [] (alignmentModeInfernal modelConstruction)+      constructModel nextModelConstructionInput staticOptions+      copyFile lastIterationCMPath resultCMPath+      --debug+      --copyFile lastIterationCMPath (resultCMPath ++ ".bak2")+      copyFile lastIterationFastaPath resultFastaPath+      copyFile lastIterationAlignmentPath resultAlignmentPath+      logMessage (iterationSummaryLog nextModelConstructionInput) outputDirectory+      logVerboseMessage (verbositySwitch staticOptions) (show nextModelConstructionInput) outputDirectory+      _ <- systemCMcalibrate "standard" (cpuThreads staticOptions) resultCMPath resultCMLogPath+      systemCMalign ("--outformat=Clustal --cpu " ++ show (cpuThreads staticOptions)) resultCMPath resultFastaPath resultClustalFilepath+      writeFile (iterationDirectory ++ "done") ""+      return nextModelConstructionInput++---------------------------------------------------------++alignmentConstructionWithCandidates :: Maybe Taxon -> Maybe Int -> SearchResult -> StaticOptions -> ModelConstruction -> IO ModelConstruction+alignmentConstructionWithCandidates currentTaxonomicContext currentUpperTaxonomyLimit searchResults staticOptions modelConstruction = do+    --candidates usedUpperTaxonomyLimit blastDatabaseSize+    let currentIterationNumber = iterationNumber modelConstruction+    let iterationDirectory = tempDirPath staticOptions ++ show currentIterationNumber ++ "/"+    --let usedUpperTaxonomyLimit = (snd (head candidates))+    --align search result+    (alignmentResults,potentialMemberEntries) <- catchAll (alignCandidates staticOptions modelConstruction "" searchResults)+                        (\e -> do logWarning ("Warning: Alignment results iteration" ++ show (iterationNumber modelConstruction) ++ " - exception: " ++ show e) (tempDirPath staticOptions)+                                  return ([],[]))+    let currentPotentialMembers = [SearchResult potentialMemberEntries (blastDatabaseSize searchResults)]+    if (null alignmentResults) && not (alignmentModeInfernal modelConstruction)+      then do+        logVerboseMessage (verbositySwitch staticOptions) ("Alignment construction with candidates - length 1 - inital mode" ++ "\n") (tempDirPath staticOptions)+        --too few sequences for alignment. because of lack in sequences no cm was constructed before+        --reusing previous modelconstruction with increased upperTaxonomyLimit but include found sequence+        --prepare next iteration+        let newTaxEntries = taxRecords modelConstruction ++ buildTaxRecords alignmentResults currentIterationNumber+        let nextModelConstructionInputWithThreshold = modelConstruction {iterationNumber = currentIterationNumber + 1,upperTaxonomyLimit = currentUpperTaxonomyLimit, taxRecords = newTaxEntries,taxonomicContext = currentTaxonomicContext}+        logMessage (iterationSummaryLog nextModelConstructionInputWithThreshold) (tempDirPath staticOptions)+        logVerboseMessage (verbositySwitch staticOptions)  (show nextModelConstructionInputWithThreshold) (tempDirPath staticOptions)     ----+        writeFile (iterationDirectory ++ "done") ""+        modelConstructer staticOptions nextModelConstructionInputWithThreshold+      else+        if (alignmentModeInfernal modelConstruction)+          then do+            logVerboseMessage (verbositySwitch staticOptions) ("Alignment construction with candidates - infernal mode\n") (tempDirPath staticOptions)+            --prepare next iteration+            let nextModelConstructionInput = constructNext currentIterationNumber modelConstruction alignmentResults currentUpperTaxonomyLimit currentTaxonomicContext [] currentPotentialMembers True+            constructModel nextModelConstructionInput staticOptions+            writeFile (iterationDirectory ++ "done") ""+            logMessage (iterationSummaryLog nextModelConstructionInput) (tempDirPath staticOptions)+            logVerboseMessage (verbositySwitch staticOptions)  (show nextModelConstructionInput) (tempDirPath staticOptions)+            --select queries+            currentSelectedQueries <- selectQueries staticOptions modelConstruction alignmentResults+            let nextModelConstructionInputWithQueries = nextModelConstructionInput {selectedQueries = currentSelectedQueries}+            nextModelConstruction <- modelConstructer staticOptions nextModelConstructionInputWithQueries+            return nextModelConstruction+          else do+            logVerboseMessage (verbositySwitch staticOptions) ("Alignment construction with candidates - initial mode\n") (tempDirPath staticOptions)+            --First round enough candidates are available for modelconstruction, alignmentModeInfernal is set to true after this iteration+            --prepare next iteration+            let nextModelConstructionInput = constructNext currentIterationNumber modelConstruction alignmentResults currentUpperTaxonomyLimit currentTaxonomicContext [] currentPotentialMembers False+            constructModel nextModelConstructionInput staticOptions+            currentSelectedQueries <- selectQueries staticOptions modelConstruction alignmentResults+            --select queries+            let nextModelConstructionInputWithInfernalMode = nextModelConstructionInput {alignmentModeInfernal = True, selectedQueries = currentSelectedQueries}+            logMessage (iterationSummaryLog  nextModelConstructionInputWithInfernalMode) (tempDirPath staticOptions)+            logVerboseMessage (verbositySwitch staticOptions)  (show  nextModelConstructionInputWithInfernalMode) (tempDirPath staticOptions)+            writeFile (iterationDirectory ++ "done") ""+            nextModelConstruction <- modelConstructer staticOptions nextModelConstructionInputWithInfernalMode+            return nextModelConstruction++alignmentConstructionWithoutCandidates :: Maybe Taxon -> Maybe Int ->  StaticOptions -> ModelConstruction -> IO ModelConstruction+alignmentConstructionWithoutCandidates currentTaxonomicContext upperTaxLimit staticOptions modelConstruction = do+    let currentIterationNumber = iterationNumber modelConstruction+    let iterationDirectory = tempDirPath staticOptions ++ show currentIterationNumber ++ "/"+    --Found no new candidates in this iteration, reusing previous modelconstruction with increased upperTaxonomyLimit+    let nextModelConstructionInputWithThreshold = modelConstruction  {iterationNumber = currentIterationNumber + 1,upperTaxonomyLimit = upperTaxLimit,taxonomicContext = currentTaxonomicContext}+    --copy model and alignment from last iteration in place if present+    let previousIterationCMPath = tempDirPath staticOptions ++ show (currentIterationNumber - 1) ++ "/model.cm"+    previousIterationCMexists <- doesFileExist previousIterationCMPath+    if previousIterationCMexists+      then do+        logVerboseMessage (verbositySwitch staticOptions) "Alignment construction no candidates - previous cm\n" (tempDirPath staticOptions)+        let previousIterationFastaPath = tempDirPath staticOptions ++ show (currentIterationNumber - 1) ++ "/model.fa"+        let previousIterationAlignmentPath = tempDirPath staticOptions ++ show (currentIterationNumber - 1) ++ "/model.stockholm"+        let thisIterationFastaPath = tempDirPath staticOptions ++ show (currentIterationNumber) ++ "/model.fa"+        let thisIterationAlignmentPath = tempDirPath staticOptions ++ show (currentIterationNumber) ++ "/model.stockholm"+        let thisIterationCMPath = tempDirPath staticOptions ++ show (currentIterationNumber) ++ "/model.cm"+        copyFile previousIterationFastaPath thisIterationFastaPath+        copyFile previousIterationAlignmentPath thisIterationAlignmentPath+        copyFile previousIterationCMPath thisIterationCMPath+        logMessage (iterationSummaryLog nextModelConstructionInputWithThreshold) (tempDirPath staticOptions)+        logVerboseMessage (verbositySwitch staticOptions) (show nextModelConstructionInputWithThreshold) (tempDirPath staticOptions)+        writeFile (iterationDirectory ++ "done") ""+        modelConstructer staticOptions nextModelConstructionInputWithThreshold+      else do+        logVerboseMessage (verbositySwitch staticOptions) "Alignment construction no candidates - no previous iteration cm\n" (tempDirPath staticOptions)+        logMessage (iterationSummaryLog nextModelConstructionInputWithThreshold) (tempDirPath staticOptions)+        logVerboseMessage (verbositySwitch staticOptions) (show nextModelConstructionInputWithThreshold) (tempDirPath staticOptions)    ----+        writeFile (iterationDirectory ++ "done") ""+        modelConstructer staticOptions nextModelConstructionInputWithThreshold++findTaxonomyStart :: Bool -> Int -> Maybe String -> String -> Fasta () () -> IO Int+findTaxonomyStart offlineMode threads inputBlastDatabase temporaryDirectory querySequence = do+  let queryIndexString = "1"+  let hitNumberQuery = buildHitNumberQuery "&HITLIST_SIZE=10"+  let registrationInfo = buildRegistration "RNAlien" "florian.eggenhofer@univie.ac.at"+  let blastQuery = BlastHTTPQuery (Just "ncbi") (Just "blastn") inputBlastDatabase [querySequence] (Just (hitNumberQuery ++ registrationInfo)) (Just (5400000000 :: Int))+  logMessage "No tax id provided - Sending find taxonomy start blast query \n" temporaryDirectory+  let logFileDirectoryPath =  temporaryDirectory ++ "taxonomystart" ++ "/"+  createDirectory logFileDirectoryPath+  blastOutput <-if offlineMode+                  then CE.catch (blast logFileDirectoryPath threads Nothing Nothing (Just (10 :: Double)) False blastQuery)+                         (\e -> do let err = show (e :: CE.IOException)+                                   logWarning ("Warning: Blast attempt failed:" ++ " " ++ err) logFileDirectoryPath+                                   return (Left ""))+                  else CE.catch (blastHTTP blastQuery)+                         (\e -> do let err = show (e :: CE.IOException)+                                   logWarning ("Warning: Blast attempt failed:" ++ " " ++ err) logFileDirectoryPath+                                   return (Left ""))+  writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString  ++ "_1blastOutput") (show blastOutput)+  logEither blastOutput temporaryDirectory+  let blastHitsArePresent = either (const False) blastMatchesPresent blastOutput+  if blastHitsArePresent+     then do+       let rightBlast = fromRight blastOutput+       let bestHit = getBestHit rightBlast+       bestBlastHitTaxIdOutput <- retrieveBlastHitTaxIdEntrez [bestHit]+       let taxIdFromEntrySummaries = extractTaxIdFromEntrySummaries (snd bestBlastHitTaxIdOutput)+       Control.Monad.when (null taxIdFromEntrySummaries) (error "findTaxonomyStart: - head: empty list of taxonomy entry summary for best hit")+       let rightBestTaxIdResult = head taxIdFromEntrySummaries+       logMessage ("Initial TaxId: " ++ show rightBestTaxIdResult ++ "\n") temporaryDirectory+       CE.evaluate rightBestTaxIdResult+     else error "Find taxonomy start: Could not find blast hits to use as a taxonomic starting point"++searchCandidates :: StaticOptions -> Maybe String -> Int ->  Maybe Int -> Maybe Int -> Double -> [Fasta () ()] -> IO SearchResult+searchCandidates staticOptions finaliterationprefix iterationnumber upperTaxLimit lowerTaxLimit expectThreshold inputQuerySequences = do+  Control.Monad.when (null inputQuerySequences) $ error "searchCandidates: - head: empty list of query sequences"+  let queryLength = fromIntegral (B.length (_bioSequence (_fasta (head inputQuerySequences))))+  let queryIndexString = "1"+  let entrezTaxFilter = buildTaxFilterQuery upperTaxLimit lowerTaxLimit+  logVerboseMessage (verbositySwitch staticOptions) ("entrezTaxFilter" ++ show entrezTaxFilter ++ "\n") (tempDirPath staticOptions)+  let hitNumberQuery = buildHitNumberQuery "&HITLIST_SIZE=5000&EXPECT=" ++ show expectThreshold+  let registrationInfo = buildRegistration "RNAlien" "florian.eggenhofer@univie.ac.at"+  let softmaskFilter = if blastSoftmaskingToggle staticOptions then "&FILTER=True&FILTER=m" else ""+  let blastQuery = BlastHTTPQuery (Just "ncbi") (Just "blastn") (blastDatabase staticOptions) inputQuerySequences  (Just (hitNumberQuery ++ entrezTaxFilter ++ softmaskFilter ++ registrationInfo)) (Just (5400000000 :: Int))+  --appendFile "/scratch/egg/blasttest/queries" ("\nBlast query:\n"  ++ show blastQuery ++ "\n")+  logVerboseMessage (verbositySwitch staticOptions) ("Sending blast query " ++ show iterationnumber ++ "\n") (tempDirPath staticOptions)+  let logFileDirectoryPath = tempDirPath staticOptions ++ show iterationnumber ++ "/" ++ fromMaybe "" finaliterationprefix ++ "log"+  logDirectoryPresent <- doesDirectoryExist logFileDirectoryPath+  Control.Monad.when (not logDirectoryPresent) $ createDirectory (logFileDirectoryPath)+  blastOutput <- if (offline staticOptions)+                  then CE.catch (blast logFileDirectoryPath  (cpuThreads staticOptions) upperTaxLimit lowerTaxLimit (Just expectThreshold) (blastSoftmaskingToggle staticOptions) blastQuery)+                         (\e -> do let err = show (e :: CE.IOException)+                                   logWarning ("Warning: Blast attempt failed:" ++ " " ++ err) (tempDirPath staticOptions)+                                   return (Left ""))+                  else CE.catch (blastHTTP blastQuery)+                         (\e -> do let err = show (e :: CE.IOException)+                                   logWarning ("Warning: Blast attempt failed:" ++ " " ++ err) (tempDirPath staticOptions)+                                   return (Left ""))+  writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString  ++ "_1blastOutput") (show blastOutput)+  logEither blastOutput (tempDirPath staticOptions)+  let blastHitsArePresent = either (const False) blastMatchesPresent blastOutput+  if blastHitsArePresent+     then do+       let rightBlast = fromRight blastOutput+       -- bestBlastHitTaxIdOutput <- retrieveBlastHitTaxIdEntrez [bestHit]+       -- let taxIdFromEntrySummaries = extractTaxIdFromEntrySummaries bestBlastHitTaxIdOutput+       -- if (null taxIdFromEntrySummaries) then (error "searchCandidates: - head: empty list of taxonomy entry summary for best hit")  else return ()+       -- let rightBestTaxIdResult = head taxIdFromEntrySummaries+       -- logVerboseMessage (verbositySwitch staticOptions) ("rightbestTaxIdResult: " ++ (show rightBestTaxIdResult) ++ "\n") (tempDirPath staticOptions)+       let blastHits = J._hits (J._search . J._results . J._report . J._blastoutput2 $ rightBlast)+       writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString  ++ "_2blastHits") (showlines blastHits)+       --filter by length+       let blastHitsFilteredByLength = filterByHitLength blastHits queryLength (lengthFilterToggle staticOptions)+       writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString  ++ "_3blastHitsFilteredByLength") (showlines blastHitsFilteredByLength)+       let blastHitsFilteredByCoverage = filterByCoverage blastHitsFilteredByLength queryLength (coverageFilterToggle staticOptions)+       writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString  ++ "_3ablastHitsFilteredByLength") (showlines blastHitsFilteredByCoverage)+       --tag BlastHits with TaxId+       --blastHitsWithTaxIdOutput <- retrieveBlastHitsTaxIdEntrez blastHitsFilteredByCoverage+       let blastHitsWithTaxId = extractBlastHitsTaxId blastHitsFilteredByCoverage+       --let uncheckedBlastHitsWithTaxIdList = map (Control.Arrow.second extractTaxIdFromEntrySummaries) blastHitsWithTaxIdOutput+       --let checkedBlastHitsWithTaxId = filter (\(_,taxids) -> not (null taxids)) uncheckedBlastHitsWithTaxIdList+       --todo checked blasthittaxidswithblasthits need to be merged as taxid blasthit pairs+       --let blastHitsWithTaxId = zip (concatMap fst checkedBlastHitsWithTaxId) (concatMap snd checkedBlastHitsWithTaxId)+       blastHitsWithParentTaxIdOutput <- retrieveParentTaxIdsEntrez blastHitsWithTaxId+       --let blastHitsWithParentTaxId = concat blastHitsWithParentTaxIdOutput+       -- filter by ParentTaxId (only one hit per TaxId)+       let blastHitsFilteredByParentTaxIdWithParentTaxId = filterByParentTaxId blastHitsWithParentTaxIdOutput True+       --let blastHitsFilteredByParentTaxId = map fst blastHitsFilteredByParentTaxIdWithParentTaxId+       writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString ++ "_4blastHitsFilteredByParentTaxId") (showlines blastHitsFilteredByParentTaxIdWithParentTaxId)+       -- Filtering with TaxTree (only hits from the same subtree as besthit)+       --let blastHitsWithTaxId = zip blastHitsFilteredByParentTaxId blastHittaxIdList+       --let (_, filteredBlastResults) = filterByNeighborhoodTreeConditional alignndmentModeInfernalToggle upperTaxLimit blastHitsWithTaxId (inputTaxNodes staticOptions) (fromJust upperTaxLimit) (singleHitperTaxToggle staticOptions)+       --writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString ++ "_5filteredBlastResults") (showlines filteredBlastResults)+       -- Coordinate generation+       let nonEmptyfilteredBlastResults = filter (\(blasthit,_) -> not (null (J._hsps blasthit))) blastHitsFilteredByParentTaxIdWithParentTaxId+       let requestedSequenceElements = map (getRequestedSequenceElement queryLength) nonEmptyfilteredBlastResults+       writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString ++  "_6requestedSequenceElements") (showlines requestedSequenceElements)+       -- Retrieval of full sequences from entrez+       --fullSequencesWithSimilars <- retrieveFullSequences requestedSequenceElements+       fullSequencesWithSimilars <- retrieveFullSequences staticOptions requestedSequenceElements+       if null fullSequencesWithSimilars+         then do+           writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString ++ "_10afullSequencesWithSimilars") "No sequences retrieved"+           CE.evaluate (SearchResult [] Nothing)+         else do+           writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString ++ "_10afullSequencesWithSimilars") (showlines fullSequencesWithSimilars)+           let fullSequences = filterIdenticalSequences fullSequencesWithSimilars 100+           --let fullSequencesWithOrigin = map (\(parsedFasta,taxid,seqSubject) -> (parsedFasta,taxid,seqSubject,'B')) fullSequences+           writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString ++ "_10fullSequences") (showlines fullSequences)+           let maybeFractionEvalueMatch = getHitWithFractionEvalue rightBlast+           if isNothing maybeFractionEvalueMatch+             then CE.evaluate (SearchResult [] Nothing)+             else do+               let fractionEvalueMatch = fromJust maybeFractionEvalueMatch+               let dbSize = computeDataBaseSize (J._evalue fractionEvalueMatch) (J._bit_score fractionEvalueMatch) (fromIntegral queryLength ::Double)+               CE.evaluate (SearchResult fullSequences (Just dbSize))+     else CE.evaluate (SearchResult [] Nothing)++-- |Computes size of blast db in Mb+computeDataBaseSize :: Double -> Double -> Double -> Double+computeDataBaseSize evalue bitscore querylength = ((evalue * 2 ** bitscore) / querylength)/10^(6 :: Integer)++alignCandidates :: StaticOptions -> ModelConstruction -> String -> SearchResult -> IO ([(Fasta () (),Int,B.ByteString)],[(Fasta () (),Int,B.ByteString)])+alignCandidates staticOptions modelConstruction multipleSearchResultPrefix searchResults = do+  let iterationDirectory = tempDirPath staticOptions ++ show (iterationNumber modelConstruction) ++ "/" ++ multipleSearchResultPrefix+  createDirectoryIfMissing False (iterationDirectory ++ "log")+  if null (candidates searchResults)+    then do+      writeFile (iterationDirectory ++ "log" ++ "/11candidates") "No candidates to align"+      return ([],[])+    else do+      --refilter for similarity+      writeFile (iterationDirectory ++ "log" ++ "/11candidates") (showlines (candidates searchResults))+      let alignedSequences = map snd (V.toList (extractAlignedSequences (iterationNumber modelConstruction) modelConstruction))+      let filteredCandidates = filterWithCollectedSequences (candidates searchResults) alignedSequences 99+      writeFile (iterationDirectory ++ "log" ++ "/12candidatesFilteredByCollected") (showlines filteredCandidates)+      if alignmentModeInfernal modelConstruction+        then alignCandidatesInfernalMode staticOptions modelConstruction multipleSearchResultPrefix (blastDatabaseSize searchResults) filteredCandidates+        else alignCandidatesInitialMode staticOptions modelConstruction multipleSearchResultPrefix filteredCandidates++alignCandidatesInfernalMode :: StaticOptions -> ModelConstruction -> String -> Maybe Double -> [(Fasta () (),Int,B.ByteString)] -> IO ([(Fasta () (),Int,B.ByteString)],[(Fasta () (),Int,B.ByteString)])+alignCandidatesInfernalMode staticOptions modelConstruction multipleSearchResultPrefix blastDbSize filteredCandidates = do+  let iterationDirectory = tempDirPath staticOptions ++ show (iterationNumber modelConstruction) ++ "/" ++ multipleSearchResultPrefix+  let candidateSequences = extractCandidateSequences filteredCandidates+  logVerboseMessage (verbositySwitch staticOptions) "Alignment Mode Infernal\n" (tempDirPath staticOptions)+  let indexedCandidateSequenceList = V.toList candidateSequences+  let cmSearchFastaFilePaths = map (constructFastaFilePaths iterationDirectory) indexedCandidateSequenceList+  let cmSearchFilePaths = map (constructCMsearchFilePaths iterationDirectory) indexedCandidateSequenceList+  let covarianceModelPath = tempDirPath staticOptions ++ show (iterationNumber modelConstruction - 1) ++ "/" ++ "model.cm"+  mapM_ (\(number,_nucleotideSequence) -> writeFastaFile (iterationDirectory ++ show number ++ ".fa") [_nucleotideSequence]) indexedCandidateSequenceList+  let zippedFastaCMSearchResultPaths = zip cmSearchFastaFilePaths cmSearchFilePaths+  --check with cmSearch+  mapM_ (uncurry (systemCMsearch (cpuThreads staticOptions) ("-Z " ++ show (fromJust blastDbSize)) covarianceModelPath)) zippedFastaCMSearchResultPaths+  cmSearchResults <- mapM readCMSearch cmSearchFilePaths+  writeFile (iterationDirectory ++ "cm_error") (concatMap show (lefts cmSearchResults))+  let rightCMSearchResults = rights cmSearchResults+  let cmSearchCandidatesWithSequences = zip rightCMSearchResults filteredCandidates+  let (trimmedSelectedCandidates,potentialCandidates,rejectedCandidates) = evaluePartitionTrimCMsearchHits (evalueThreshold modelConstruction) cmSearchCandidatesWithSequences+  createDirectoryIfMissing False (iterationDirectory ++ "log")+  writeFile (iterationDirectory ++ "log" ++ "/13selectedCandidates'") (showlines trimmedSelectedCandidates)+  writeFile (iterationDirectory ++ "log" ++ "/14rejectedCandidates'") (showlines rejectedCandidates)+  writeFile (iterationDirectory ++ "log" ++ "/15potentialCandidates'") (showlines potentialCandidates)+  return (map snd trimmedSelectedCandidates,map snd potentialCandidates)++alignCandidatesInitialMode :: StaticOptions -> ModelConstruction -> String -> [(Fasta () (),Int,B.ByteString)] -> IO ([(Fasta () (),Int,B.ByteString)],[(Fasta () (),Int,B.ByteString)])+alignCandidatesInitialMode staticOptions modelConstruction multipleSearchResultPrefix filteredCandidates = do+  let iterationDirectory = tempDirPath staticOptions ++ show (iterationNumber modelConstruction) ++ "/" ++ multipleSearchResultPrefix+  --writeFile (iterationDirectory ++ "log" ++ "/11bcandidates") (showlines filteredCandidates)+  createDirectoryIfMissing False (iterationDirectory ++ "log")+  let candidateSequences = extractCandidateSequences filteredCandidates+  --writeFile (iterationDirectory ++ "log" ++ "/11ccandidates") (showlines (V.toList candidateSequences))+  logVerboseMessage (verbositySwitch staticOptions) "Alignment Mode Initial\n" (tempDirPath staticOptions)+  --write Fasta sequences+  let inputFastaFilepath = iterationDirectory ++ "input.fa"+  let inputFoldFilepath = iterationDirectory ++ "input.fold"+  writeFastaFile (iterationDirectory ++ "input.fa") [(head (inputFasta modelConstruction))]+  logMessage (showlines (V.toList candidateSequences)) (tempDirPath staticOptions)+  V.mapM_ (\(number,nucleotideSequence') -> writeFastaFile (iterationDirectory ++ show number ++ ".fa") [nucleotideSequence']) candidateSequences+  let candidateFastaFilepath = V.toList (V.map (\(number,_) -> iterationDirectory ++ show number ++ ".fa") candidateSequences)+  let candidateFoldFilepath = V.toList (V.map (\(number,_) -> iterationDirectory ++ show number ++ ".fold") candidateSequences)+  let locarnainClustalw2FormatFilepath =  V.toList (V.map (\(number,_) -> iterationDirectory ++ show number ++ "." ++ "clustalmlocarna") candidateSequences)+  let candidateAliFoldFilepath = V.toList (V.map (\(number,_) -> iterationDirectory ++ show number ++ ".alifold") candidateSequences)+  let locarnaFilepath = V.toList (V.map (\(number,_) -> iterationDirectory ++ show number ++ "." ++ "mlocarna") candidateSequences)+  alignSequences "locarna" " --write-structure --free-endgaps=++-- " (replicate (V.length candidateSequences) inputFastaFilepath) candidateFastaFilepath locarnainClustalw2FormatFilepath locarnaFilepath+  --compute SequenceIdentities+  let sequenceIdentities = V.map (\(_,s) -> sequenceIdentity (head (inputFasta modelConstruction)) s/(100 :: Double)) candidateSequences+  --compute SCI+  systemRNAfold inputFastaFilepath inputFoldFilepath+  inputfoldResult <- readRNAfold inputFoldFilepath+  let inputFoldMFE = foldingEnergy (fromRight inputfoldResult)+  mapM_ (uncurry systemRNAfold) (zip candidateFastaFilepath candidateFoldFilepath)+  foldResults <- mapM readRNAfold candidateFoldFilepath+  let candidateMFEs = map (foldingEnergy . fromRight) foldResults+  let averageMFEs = map (\candidateMFE -> (candidateMFE + inputFoldMFE)/2) candidateMFEs+  mapM_ (uncurry (systemRNAalifold "")) (zip locarnainClustalw2FormatFilepath candidateAliFoldFilepath)+  alifoldResults <- mapM readRNAalifold candidateAliFoldFilepath+  let consensusMFE = map (alignmentConsensusMinimumFreeEnergy . fromRight) alifoldResults+  let sciidfraction = map (\(consMFE,averMFE,seqId) -> (consMFE/averMFE)/seqId) (zip3 consensusMFE averageMFEs (V.toList sequenceIdentities))+  let idlog = concatMap (\(sciidfraction',consMFE,averMFE,seqId) -> show sciidfraction' ++ "," ++ show consMFE ++ "," ++ show averMFE ++ "," ++ show seqId ++ "\n")(zip4 sciidfraction consensusMFE averageMFEs (V.toList sequenceIdentities))+  writeFile (iterationDirectory ++ "log" ++ "/idlog") idlog+  let alignedCandidates = zip sciidfraction filteredCandidates+  writeFile (iterationDirectory ++ "log" ++ "/zscores") (showlines alignedCandidates)+  let (selectedCandidates,rejectedCandidates) = partition (\(sciidfraction',_) -> sciidfraction' > nSCICutoff staticOptions) alignedCandidates+  mapM_ print (zip3 consensusMFE averageMFEs (V.toList sequenceIdentities))+  writeFile (iterationDirectory ++ "log" ++ "/13selectedCandidates") (showlines selectedCandidates)+  writeFile (iterationDirectory ++ "log" ++ "/14rejectedCandidates") (showlines rejectedCandidates)+  return (map snd selectedCandidates,[])++setClusterNumber :: Int -> Int+setClusterNumber x+  | x <= 5 = x+  | otherwise = 5++findCutoffforClusterNumber :: Dendrogram a -> Int -> Distance -> Distance+findCutoffforClusterNumber clustaloDendrogram numberOfClusters currentCutoff+  | currentClusterNumber >= numberOfClusters = currentCutoff+  | otherwise = findCutoffforClusterNumber clustaloDendrogram numberOfClusters (currentCutoff-0.01)+    where currentClusterNumber = length (cutAt clustaloDendrogram currentCutoff)++-- Selects Query sequence ids from all collected seqeuences. Queries are then fetched by extractQueries function.+selectQueries :: StaticOptions -> ModelConstruction -> [(Fasta () (),Int,B.ByteString)] -> IO [Fasta () ()]+selectQueries staticOptions modelConstruction selectedCandidates = do+  logVerboseMessage (verbositySwitch staticOptions) "SelectQueries\n" (tempDirPath staticOptions)+  --Extract sequences from modelconstruction+  let alignedSequences = extractAlignedSequences (iterationNumber modelConstruction) modelConstruction+  let candidateSequences = extractQueryCandidates selectedCandidates+  let iterationDirectory = tempDirPath staticOptions ++ show (iterationNumber modelConstruction) ++ "/"+  let stockholmFilepath = iterationDirectory ++ "model" ++ ".stockholm"+  let alignmentSequences = map snd (V.toList (V.concat [candidateSequences,alignedSequences]))+  if length alignmentSequences > 3+    then+      if (querySelectionMethod staticOptions) == "clustering"+        then do+          --write Fasta sequences+          writeFastaFile (iterationDirectory ++ "query" ++ ".fa") alignmentSequences+          let fastaFilepath = iterationDirectory ++ "query" ++ ".fa"+          let clustaloFilepath = iterationDirectory ++ "query" ++ ".clustalo"+          let clustaloDistMatrixPath = iterationDirectory ++ "query" ++ ".matrix"+          alignSequences "clustalo" ("--full --distmat-out=" ++ clustaloDistMatrixPath ++ " ") [fastaFilepath] [] [clustaloFilepath] []+          idsDistancematrix <- readClustaloDistMatrix clustaloDistMatrixPath+          logEither idsDistancematrix (tempDirPath staticOptions)+          let (clustaloIds,clustaloDistMatrix) = fromRight idsDistancematrix+          logVerboseMessage (verbositySwitch staticOptions) ("Clustalid: " ++ intercalate "," clustaloIds ++ "\n") (tempDirPath staticOptions)+          logVerboseMessage (verbositySwitch staticOptions) ("Distmatrix: " ++ show clustaloDistMatrix ++ "\n") (tempDirPath staticOptions)+          let clustaloDendrogram = dendrogram UPGMA clustaloIds (getDistanceMatrixElements clustaloIds clustaloDistMatrix)+          logVerboseMessage (verbositySwitch staticOptions) ("ClustaloDendrogram: " ++ show  clustaloDendrogram ++ "\n") (tempDirPath staticOptions)+          logVerboseMessage (verbositySwitch staticOptions) ("ClustaloDendrogram: " ++ show clustaloDistMatrix ++ "\n") (tempDirPath staticOptions)+          let numberOfClusters = setClusterNumber (length alignmentSequences)+          logVerboseMessage (verbositySwitch staticOptions) ("numberOfClusters: " ++ show numberOfClusters ++ "\n") (tempDirPath staticOptions)+          let dendrogramStartCutDistance = 1 :: Double+          let dendrogramCutDistance' = findCutoffforClusterNumber clustaloDendrogram numberOfClusters dendrogramStartCutDistance+          logVerboseMessage (verbositySwitch staticOptions) ("dendrogramCutDistance': " ++ show dendrogramCutDistance' ++ "\n") (tempDirPath staticOptions)+          let cutDendrogram = cutAt clustaloDendrogram dendrogramCutDistance'+          --putStrLn "cutDendrogram: "+          --print cutDendrogram+          let currentSelectedSequenceIds = map B.pack (take (queryNumber staticOptions) (concatMap (take 1 . elements) cutDendrogram))+          --let alignedSequences = fastaSeqData:map nucleotideSequence (concatMap sequenceRecords (taxRecords modelconstruction))+          let fastaSelectedSequences = concatMap (filterSequenceById alignmentSequences) currentSelectedSequenceIds+          stockholmSelectedSequences <- extractAlignmentSequencesByIds stockholmFilepath currentSelectedSequenceIds+          --Stockholm sequnces contain conservation annotation from cmalign in infernal mode+          let currentSelectedSequences = if (blastSoftmaskingToggle staticOptions) then stockholmSelectedSequences else fastaSelectedSequences+          --let currentSelectedQueries = concatMap (\querySeqId -> filter (\alignedSeq -> L.unpack (fastaHeader alignedSeq) == querySeqId) alignmentSequences) querySeqIds+          logVerboseMessage (verbositySwitch staticOptions) ("SelectedQueries: " ++ show currentSelectedSequences ++ "\n") (tempDirPath staticOptions)+          writeFile (tempDirPath staticOptions ++ show (iterationNumber modelConstruction) ++ "/log" ++ "/13selectedQueries") (showlines currentSelectedSequences)+          CE.evaluate currentSelectedSequences+        else do+          let fastaSelectedSequences = filterIdenticalSequences' alignmentSequences (95 :: Double)+          let currentSelectedSequenceIds = map fastaHeader (take (queryNumber staticOptions) fastaSelectedSequences)+          stockholmSelectedSequences <- extractAlignmentSequencesByIds stockholmFilepath currentSelectedSequenceIds+          let currentSelectedSequences = if (blastSoftmaskingToggle staticOptions) then stockholmSelectedSequences else fastaSelectedSequences+          writeFile (tempDirPath staticOptions ++ show (iterationNumber modelConstruction) ++ "/log" ++ "/13selectedQueries") (showlines currentSelectedSequences)+          CE.evaluate currentSelectedSequences+    else return []+++fastaHeader :: Fasta () () -> B.ByteString+fastaHeader currentFasta = _sequenceIdentifier . _header $ currentFasta++filterSequenceById :: [Fasta () ()] -> B.ByteString-> [Fasta () ()]+filterSequenceById alignmentSequences querySequenceId = filter (seqenceHasId querySequenceId) alignmentSequences++seqenceHasId :: B.ByteString -> Fasta () () -> Bool+seqenceHasId querySequenceId alignmentSequence = fastaHeader alignmentSequence == querySequenceId++constructModel :: ModelConstruction -> StaticOptions -> IO String+constructModel modelConstruction staticOptions = do+  --Extract sequences from modelconstruction+  let alignedSequences = extractAlignedSequences (iterationNumber modelConstruction) modelConstruction+  --The CM resides in the iteration directory where its input alignment originates from+  let outputDirectory = tempDirPath staticOptions ++ show (iterationNumber modelConstruction - 1) ++ "/"+  let alignmentSequences = map snd (V.toList (V.concat [alignedSequences]))+  --write Fasta sequences+  writeFastaFile (outputDirectory ++ "model" ++ ".fa") alignmentSequences+  let fastaFilepath = outputDirectory ++ "model" ++ ".fa"+  let locarnaFilepath = outputDirectory ++ "model" ++ ".mlocarna"+  let stockholmFilepath = outputDirectory ++ "model" ++ ".stockholm"+  --- let reformatedClustalFilepath = outputDirectory ++ "model" ++ ".clustal.reformated"+  let updatedStructureStockholmFilepath = outputDirectory ++ "newstructuremodel" ++ ".stockholm"+  let cmalignCMFilepath = tempDirPath staticOptions ++ show (iterationNumber modelConstruction - 2) ++ "/" ++ "model" ++ ".cm"+  let cmFilepath = outputDirectory ++ "model" ++ ".cm"+  let cmCalibrateFilepath = outputDirectory ++ "model" ++ ".cmcalibrate"+  let cmBuildFilepath = outputDirectory ++ "model" ++ ".cmbuild"+  let alifoldFilepath = outputDirectory ++ "model" ++ ".alifold"+  let refinedAlignmentFilepath = outputDirectory ++ "modelrefined" ++ ".stockholm"+  let cmBuildOptions ="--refine " ++ refinedAlignmentFilepath+  if alignmentModeInfernal modelConstruction+     then do+       logVerboseMessage (verbositySwitch staticOptions) "Construct Model - infernal mode\n" (tempDirPath staticOptions)+       systemCMalign ("--cpu " ++ show (cpuThreads staticOptions)) cmalignCMFilepath fastaFilepath stockholmFilepath+       systemRNAalifold "-r --cfactor 0.6 --nfactor 0.5" stockholmFilepath alifoldFilepath+       replaceStatus <- replaceStockholmStructure stockholmFilepath alifoldFilepath updatedStructureStockholmFilepath+       if null replaceStatus+         then do+           systemCMbuild cmBuildOptions updatedStructureStockholmFilepath cmFilepath cmBuildFilepath+           systemCMcalibrate "fast" (cpuThreads staticOptions) cmFilepath cmCalibrateFilepath+           return cmFilepath+         else do+           logWarning ("Warning: A problem occured updating the secondary structure of iteration " ++ show (iterationNumber modelConstruction)  ++ " stockholm alignment: " ++ replaceStatus) (tempDirPath staticOptions)+           systemCMbuild cmBuildOptions stockholmFilepath cmFilepath cmBuildFilepath+           systemCMcalibrate "fast" (cpuThreads staticOptions) cmFilepath cmCalibrateFilepath+           return cmFilepath+     else do+       logVerboseMessage (verbositySwitch staticOptions) "Construct Model - initial mode\n" (tempDirPath staticOptions)+       alignSequences "mlocarna" ("--threads=" ++ show (cpuThreads staticOptions) ++ " ") [fastaFilepath] [] [locarnaFilepath] []+       mlocarnaAlignment <- readStructuralClustalAlignment locarnaFilepath+       logEither mlocarnaAlignment (tempDirPath staticOptions)+       let stockholAlignment = convertClustaltoStockholm (fromRight mlocarnaAlignment)+       TI.writeFile stockholmFilepath stockholAlignment+       _ <- systemCMbuild cmBuildOptions stockholmFilepath cmFilepath cmBuildFilepath+       _ <- systemCMcalibrate "fast" (cpuThreads staticOptions) cmFilepath cmCalibrateFilepath+       return cmFilepath++-- | Replaces structure of input stockholm file with the consensus structure of alifoldFilepath and outputs updated stockholmfile+replaceStockholmStructure :: String -> String -> String -> IO String+replaceStockholmStructure stockholmFilepath alifoldFilepath updatedStructureStockholmFilepath = do+  inputAln <- readFile stockholmFilepath+  inputRNAalifold <- readRNAalifold alifoldFilepath+  if isLeft inputRNAalifold+    then+     return (show (fromLeft inputRNAalifold))+    else do+     let alifoldstructure = alignmentConsensusDotBracket (fromRight inputRNAalifold)+     let seedLinesVector = V.fromList (lines inputAln)+     let structureIndices = V.toList (V.findIndices isStructureLine seedLinesVector)+     let updatedStructureElements = updateStructureElements seedLinesVector alifoldstructure structureIndices+     let newVector = seedLinesVector V.// updatedStructureElements+     let newVectorString = unlines (V.toList newVector)+     writeFile updatedStructureStockholmFilepath newVectorString+     return []++updateStructureElements :: V.Vector String -> String -> [Int] -> [(Int,String)]+updateStructureElements inputVector structureString indices+  | null indices = []+  | otherwise = newElement ++ updateStructureElements inputVector (drop structureLength structureString) (tail indices)+  where currentIndex = head indices+        currentElement = inputVector V.! currentIndex+        elementLength = length currentElement+        structureStartIndex = maximum (elemIndices ' ' currentElement) + 1+        structureLength = elementLength - structureStartIndex+        newElementHeader = take structureStartIndex currentElement+        newElementStructure = take structureLength structureString+        newElement = [(currentIndex,newElementHeader ++ newElementStructure)]++isStructureLine :: String -> Bool+isStructureLine input = "#=GC SS_cons" `isInfixOf` input++-- Generates iteration string for Log+iterationSummaryLog :: ModelConstruction -> String+iterationSummaryLog mC = output+  where upperTaxonomyLimitOutput = maybe "not set" show (upperTaxonomyLimit mC)+        output = "Upper taxonomy id limit: " ++ upperTaxonomyLimitOutput ++ ", Collected members: " ++ show (length (concatMap sequenceRecords (taxRecords mC))) ++ "\n"++-- | Used for passing progress to Alien server+iterationSummary :: ModelConstruction -> StaticOptions -> IO()+iterationSummary mC sO = do+  --iteration -- tax limit -- bitscore cutoff -- blastresult -- aligned seqs --queries --fa link --aln link --cm link+  let upperTaxonomyLimitOutput = maybe "not set" show (upperTaxonomyLimit mC)+  let output = show (iterationNumber mC) ++ "," ++ upperTaxonomyLimitOutput ++ "," ++ show (length (concatMap sequenceRecords (taxRecords mC)))+  writeFile (tempDirPath sO ++ "/log/" ++ show (iterationNumber mC) ++ ".log") output++-- | Used for passing progress to Alien server+resultSummary :: ModelConstruction -> StaticOptions -> IO()+resultSummary mC sO = do+  --iteration -- tax limit -- bitscore cutoff -- blastresult -- aligned seqs --queries --fa link --aln link --cm link+  let upperTaxonomyLimitOutput = maybe "not set" show (upperTaxonomyLimit mC)+  let output = show (iterationNumber mC) ++ "," ++ upperTaxonomyLimitOutput ++ "," ++ show (length (concatMap sequenceRecords (taxRecords mC)))+  writeFile (tempDirPath sO ++ "/log/result" ++ ".log") output++readClustaloDistMatrix :: String -> IO (Either ParseError ([String],Matrix Double))+readClustaloDistMatrix = parseFromFile genParserClustaloDistMatrix++genParserClustaloDistMatrix :: GenParser Char st ([String],Matrix Double)+genParserClustaloDistMatrix = do+  _ <- many1 digit+  newline+  clustaloDistRow <- many1 (try genParserClustaloDistRow)+  eof+  return (map fst clustaloDistRow,fromLists (map snd clustaloDistRow))++genParserClustaloDistRow :: GenParser Char st (String,[Double])+genParserClustaloDistRow = do+  entryId <- many1 (noneOf " ")+  many1 space+  distances <- many1 (try genParserClustaloDistance)+  newline+  return (entryId,distances)++genParserClustaloDistance :: GenParser Char st Double+genParserClustaloDistance = do+  distance <- many1 (oneOf "1234567890.")+  optional (try (char ' ' ))+  return (readDouble distance)++getDistanceMatrixElements :: [String] -> Matrix Double -> String -> String -> Double+getDistanceMatrixElements ids distMatrix id1 id2 = distance+  -- Data.Matrix is indexed starting with 1+  where indexid1 = fromJust (elemIndex id1 ids) + 1+        indexid2 = fromJust (elemIndex id2 ids) + 1+        distance = getElem indexid1 indexid2 distMatrix++-- | Filter duplicates removes hits in sequences that were already collected. This happens during revisiting the starting subtree.+filterDuplicates :: ModelConstruction -> SearchResult -> SearchResult+filterDuplicates modelConstruction inputSearchResult = uniqueSearchResult+  where alignedSequences = map snd (V.toList (extractAlignedSequences (iterationNumber modelConstruction) modelConstruction))+        collectedIdentifiers = map fastaHeader alignedSequences+        uniques = filter (\(s,_,_) -> notElem (fastaHeader s) collectedIdentifiers) (candidates inputSearchResult)+        uniqueSearchResult = SearchResult uniques (blastDatabaseSize inputSearchResult)++-- | Filter a list of similar extended blast hits+--filterIdenticalSequencesWithOrigin :: [(Fasta,Int,String,Char)] -> Double -> [(Fasta,Int,String,Char)]+--filterIdenticalSequencesWithOrigin (headSequence:rest) identitycutoff = result+--  where filteredSequences = filter (\x -> (sequenceIdentity (firstOfQuadruple headSequence) (firstOfQuadruple x)) < identitycutoff) rest+--        result = headSequence:(filterIdenticalSequencesWithOrigin filteredSequences identitycutoff)+--filterIdenticalSequencesWithOrigin [] _ = []++-- | Filter a list of similar extended blast hits+filterIdenticalSequences :: [(Fasta () (),Int,B.ByteString)] -> Double -> [(Fasta () (),Int,B.ByteString)]+filterIdenticalSequences (headSequence:rest) identitycutoff = result+  where filteredSequences = filter (\x -> sequenceIdentity (firstOfTriple headSequence) (firstOfTriple x) < identitycutoff) rest+        result = headSequence:filterIdenticalSequences filteredSequences identitycutoff+filterIdenticalSequences [] _ = []++-- | Filter sequences too similar to already aligned sequences+filterWithCollectedSequences :: [(Fasta () (),Int,B.ByteString)] -> [Fasta () ()] -> Double -> [(Fasta () (),Int,B.ByteString)]+filterWithCollectedSequences inputCandidates collectedSequences identitycutoff = filter (isUnSimilarSequence collectedSequences identitycutoff . firstOfTriple) inputCandidates+--filterWithCollectedSequences [] [] _ = []++-- | Filter alignment entries by similiarity+filterIdenticalSequences' :: [Fasta () ()] -> Double -> [Fasta () ()]+filterIdenticalSequences' (headEntry:rest) identitycutoff = result+  where filteredEntries = filter (\ x -> sequenceIdentity headEntry x < identitycutoff) rest+        result = headEntry:filterIdenticalSequences' filteredEntries identitycutoff+filterIdenticalSequences' [] _ = []++---- | Filter alignment entries by similiarity+--filterIdenticalAlignmentEntry :: [ClustalAlignmentEntry] -> Double -> [ClustalAlignmentEntry]+--filterIdenticalAlignmentEntry (headEntry:rest) identitycutoff = result+--  where filteredEntries = filter (\x -> (stringIdentity (entryAlignedSequence headEntry) (entryAlignedSequence x)) < identitycutoff) rest+--        result = headEntry:filterIdenticalAlignmentEntry filteredEntries identitycutoff+--filterIdenticalAlignmentEntry [] _ = []++isUnSimilarSequence :: [Fasta () ()] -> Double -> Fasta () () -> Bool+isUnSimilarSequence collectedSequences identitycutoff checkSequence = any (\ x -> sequenceIdentity checkSequence x < identitycutoff) collectedSequences++firstOfTriple :: (t, t1, t2) -> t+firstOfTriple (a,_,_) = a++-- | Check if the result field of BlastResult is filled and if hits are present+blastMatchesPresent :: J.BlastJSON2 -> Bool+blastMatchesPresent blastJS2+  | null resultList = False+  | otherwise = True+  where resultList = concatMap J._hsps ((Data.Foldable.toList . J._hits . J._search . J._results . J._report . J._blastoutput2 $ blastJS2))++-- | Compute identity of sequences+textIdentity :: T.Text -> T.Text -> Double+textIdentity text1 text2 = identityPercent+   where distance = TM.hamming text1 text2+         --Replication of RNAz select sequences requires only allowing substitutions+         --costs = ED.defaultEditCosts {ED.deletionCosts = ED.ConstantCost 100,ED.insertionCosts = ED.ConstantCost 100,ED.transpositionCosts = ED.ConstantCost 100}+         maximumDistance = maximum [T.length text1, T.length text2]+         distanceDouble = toInteger ( fromJust distance )+         identityPercent = 1 - (fromIntegral distanceDouble/fromIntegral maximumDistance)+++-- | Compute identity of sequences+-- stringIdentity :: String -> String -> Double+-- stringIdentity string1 string2 = identityPercent+--    where distance = ED.levenshteinDistance costs string1 string2+--          --Replication of RNAz select sequences requires only allowing substitutions+--          costs = ED.defaultEditCosts {ED.deletionCosts = ED.ConstantCost 100,ED.insertionCosts = ED.ConstantCost 100,ED.transpositionCosts = ED.ConstantCost 100}+--          maximumDistance = maximum [length string1,length string2]+--          identityPercent = 1 - (fromIntegral distance/fromIntegral maximumDistance)++-- | Compute identity of sequences+sequenceIdentity :: Fasta () () -> Fasta () () -> Double+sequenceIdentity sequence1 sequence2 = identityPercent+  where distance = ED.levenshteinDistance ED.defaultEditCosts sequence1string sequence2string+        sequence1string = B.unpack . _bioSequence . _fasta $ sequence1+        sequence2string = B.unpack . _bioSequence . _fasta $ sequence2+        maximumDistance = maximum [length sequence1string,length sequence2string]+        identityPercent = 100 - ((fromIntegral distance/fromIntegral maximumDistance) * (read "100" ::Double))++getTaxonomicContextEntrez :: Maybe Int -> Maybe Taxon -> IO (Maybe Taxon)+getTaxonomicContextEntrez upperTaxLimit currentTaxonomicContext =+  if isJust upperTaxLimit+      then if isJust currentTaxonomicContext+        then return currentTaxonomicContext+        else retrieveTaxonomicContextEntrez (fromJust upperTaxLimit)+          --return retrievedTaxonomicContext+    else return Nothing++setTaxonomicContextEntrez :: Int -> Maybe Taxon -> Maybe Int -> (Maybe Int, Maybe Int)+setTaxonomicContextEntrez currentIterationNumber currentTaxonomicContext subTreeTaxId+  | currentIterationNumber == 0 = (subTreeTaxId, Nothing)+  | otherwise = setUpperLowerTaxLimitEntrez (fromJust subTreeTaxId) (fromJust currentTaxonomicContext)++-- setTaxonomic Context for next candidate search, the upper bound of the last search become the lower bound of the next+setUpperLowerTaxLimitEntrez :: Int -> Taxon -> (Maybe Int, Maybe Int)+setUpperLowerTaxLimitEntrez subTreeTaxId currentTaxonomicContext = (upperLimit,lowerLimit)+  where upperLimit = raiseTaxIdLimitEntrez subTreeTaxId currentTaxonomicContext+        lowerLimit = Just subTreeTaxId++raiseTaxIdLimitEntrez :: Int -> Taxon -> Maybe Int+raiseTaxIdLimitEntrez subTreeTaxId taxon = parentNodeTaxId+  where lastUpperBoundNodeIndex = fromJust (V.findIndex  (\node -> lineageTaxId node == subTreeTaxId) lineageExVector)+        linageNodeTaxId = Just (lineageTaxId (lineageExVector V.! (lastUpperBoundNodeIndex -1)))+        lineageExVector = V.fromList (lineageEx taxon)+        --the input taxid is not part of the lineage, therefor we look for further taxids in the lineage after we used the parent tax id of the input node+        parentNodeTaxId = if subTreeTaxId == taxonTaxId taxon then Just (taxonParentTaxId taxon) else linageNodeTaxId++constructNext :: Int -> ModelConstruction -> [(Fasta () (),Int,B.ByteString)] -> Maybe Int -> Maybe Taxon  -> [Fasta () ()] -> [SearchResult] -> Bool -> ModelConstruction+constructNext currentIterationNumber modelconstruction alignmentResults upperTaxLimit inputTaxonomicContext inputSelectedQueries inputPotentialMembers toggleInfernalAlignmentModeTrue = nextModelConstruction+  where newIterationNumber = currentIterationNumber + 1+        taxEntries = taxRecords modelconstruction ++ buildTaxRecords alignmentResults currentIterationNumber+        potMembers = potentialMembers modelconstruction ++ inputPotentialMembers+        currentAlignmentMode = toggleInfernalAlignmentModeTrue || alignmentModeInfernal modelconstruction+        nextModelConstruction = ModelConstruction newIterationNumber (inputFasta modelconstruction) taxEntries upperTaxLimit inputTaxonomicContext (evalueThreshold modelconstruction) currentAlignmentMode inputSelectedQueries potMembers++buildTaxRecords :: [(Fasta () (),Int,B.ByteString)] -> Int -> [TaxonomyRecord]+buildTaxRecords alignmentResults currentIterationNumber = taxonomyRecords+  where taxIdGroups = groupBy sameTaxIdAlignmentResult alignmentResults+        taxonomyRecords = map (buildTaxRecord currentIterationNumber) taxIdGroups++sameTaxIdAlignmentResult :: (Fasta () (),Int,B.ByteString) -> (Fasta () (),Int,B.ByteString) -> Bool+sameTaxIdAlignmentResult (_,taxId1,_) (_,taxId2,_) = taxId1 == taxId2++buildTaxRecord :: Int -> [(Fasta () (),Int,B.ByteString)] -> TaxonomyRecord+buildTaxRecord currentIterationNumber entries = taxRecord+  where recordTaxId = (\(_,currentTaxonomyId,_) -> currentTaxonomyId) (head entries)+        seqRecords = map (buildSeqRecord currentIterationNumber)  entries+        taxRecord = TaxonomyRecord recordTaxId seqRecords++buildSeqRecord :: Int -> (Fasta () (),Int,B.ByteString) -> SequenceRecord+buildSeqRecord currentIterationNumber (parsedFasta,_,seqSubject) = SequenceRecord parsedFasta currentIterationNumber seqSubject++-- | Partitions sequences by containing a cmsearch hit and extracts the hit region as new sequence+evaluePartitionTrimCMsearchHits :: Double -> [(CMsearch,(Fasta () (), Int, B.ByteString))] -> ([(CMsearch,(Fasta () (), Int, B.ByteString))],[(CMsearch,(Fasta () (), Int, B.ByteString))],[(CMsearch,(Fasta () (), Int, B.ByteString))])+evaluePartitionTrimCMsearchHits eValueThreshold cmSearchCandidatesWithSequences = (trimmedSelectedCandidates,potentialCandidates,rejectedCandidates)+  where potentialMemberseValueThreshold = eValueThreshold * 1000+        (prefilteredCandidates,rejectedCandidates) = partition (\(cmSearchResult,_) -> any (\hitScore' -> potentialMemberseValueThreshold >= hitEvalue hitScore') (cmsearchHits cmSearchResult)) cmSearchCandidatesWithSequences+        (selectedCandidates,potentialCandidates) = partition (\(cmSearchResult,_) -> any (\hitScore' -> eValueThreshold >= hitEvalue hitScore') (cmsearchHits cmSearchResult)) prefilteredCandidates+        trimmedSelectedCandidates = map (\(cmSearchResult,inputSequence) -> (cmSearchResult,trimCMsearchHit cmSearchResult inputSequence)) selectedCandidates+++trimCMsearchHit :: CMsearch -> (Fasta () (), Int, B.ByteString) -> (Fasta () (), Int, B.ByteString)+trimCMsearchHit cmSearchResult (inputSequence,b,c) = (subSequence,b,c)+  where hitScoreEntry = head (cmsearchHits cmSearchResult)+        sequenceString = B.unpack . _bioSequence . _fasta $ inputSequence+        sequenceSubstring = cmSearchsubString (hitStart hitScoreEntry) (hitEnd hitScoreEntry) sequenceString+        --extend original seqheader+        newSequenceHeader = SequenceIdentifier (B.pack (B.unpack (fastaHeader inputSequence) ++ "cmS_" ++ show (hitStart hitScoreEntry) ++ "_" ++ show (hitEnd hitScoreEntry) ++ "_" ++ show (hitStrand hitScoreEntry)))+        subSequence = Fasta newSequenceHeader (BioSequence (B.pack sequenceSubstring))++-- | Extract a substring with coordinates from cmsearch, first nucleotide has index 1+cmSearchsubString :: Int -> Int -> String -> String+cmSearchsubString startSubString endSubString inputString+  | startSubString < endSubString = take (endSubString - (startSubString -1))(drop (startSubString - 1) inputString)+  | startSubString > endSubString = take (reverseEnd - (reverseStart - 1))(drop (reverseStart - 1 ) (reverse inputString))+  | otherwise = take (endSubString - (startSubString -1))(drop (startSubString - 1) inputString)+  where stringLength = length inputString+        reverseStart = stringLength - (startSubString + 1)+        reverseEnd = stringLength - (endSubString - 1)++extractQueries :: Int -> ModelConstruction -> [Fasta () ()]+extractQueries foundSequenceNumber modelconstruction+  | foundSequenceNumber < 3 = fastaSeqData+  | otherwise = querySequences'+  where fastaSeqData = inputFasta modelconstruction+        querySequences' = selectedQueries modelconstruction++extractQueryCandidates :: [(Fasta () (),Int,B.ByteString)] -> V.Vector (Int,Fasta () ())+extractQueryCandidates querycandidates = indexedSeqences+  where sequences = map (\(candidateSequence,_,_) -> candidateSequence) querycandidates+        indexedSeqences = V.map (\(number,candidateSequence) -> (number + 1,candidateSequence))(V.indexed (V.fromList sequences))++buildTaxFilterQuery :: Maybe Int -> Maybe Int -> String+buildTaxFilterQuery upperTaxLimit lowerTaxLimit+  | isNothing upperTaxLimit = ""+  | isNothing lowerTaxLimit =  "&ENTREZ_QUERY=" ++ encodedTaxIDQuery (fromJust upperTaxLimit)+  | otherwise = "&ENTREZ_QUERY=" ++ "%28txid" ++ show (fromJust upperTaxLimit)  ++ "%5BORGN%5D%29" ++ "NOT" ++ "%28txid" ++ show (fromJust lowerTaxLimit) ++ "%5BORGN%5D&EQ_OP%29"++buildHitNumberQuery :: String -> String+buildHitNumberQuery hitNumber+  | hitNumber == "" = ""+  | otherwise = "&ALIGNMENTS=" ++ hitNumber++encodedTaxIDQuery :: Int -> String+encodedTaxIDQuery taxID = "txid" ++ show taxID ++ "%20%5BORGN%5D&EQ_OP"++-- | Adds cm prefix to pseudo random number+randomid :: Int16 -> String+randomid number = "cm" ++ show number++-- | Create session id for RNAlien+createSessionID :: Maybe String -> IO String+createSessionID sessionIdentificator =+  if isJust sessionIdentificator+    then return (fromJust sessionIdentificator)+    else do+      randomNumber <- randomIO :: IO Int16+      let sessionId = randomid (abs (randomNumber))+      return sessionId++-- | Run external locarna command and read the output into the corresponding datatype+systemlocarna :: String -> (String,String,String,String) -> IO ExitCode+systemlocarna options (inputFilePath1, inputFilePath2, clustalformatoutputFilePath, outputFilePath) = system ("locarna " ++ options ++ " --clustal=" ++ clustalformatoutputFilePath  ++ " " ++ inputFilePath1  ++ " " ++ inputFilePath2 ++ " > " ++ outputFilePath)++-- | Run external mlocarna command and read the output into the corresponding datatype, there is also a folder created at the location of the input fasta file+systemMlocarna :: String -> (String,String) -> IO ExitCode+systemMlocarna options (inputFilePath, outputFilePath) = system ("mlocarna " ++ options ++ " " ++ inputFilePath ++ " > " ++ outputFilePath)++-- | Run external mlocarna command and read the output into the corresponding datatype, there is also a folder created at the location of the input fasta file, the job is terminated after the timeout provided in seconds+systemMlocarnaWithTimeout :: String -> String -> (String,String) -> IO ExitCode+systemMlocarnaWithTimeout timeout options (inputFilePath, outputFilePath) = system ("timeout " ++ timeout ++"s "++ "mlocarna " ++ options ++ " " ++ inputFilePath ++ " > " ++ outputFilePath)++-- | Run external clustalo command and return the Exitcode+systemClustalw2 :: String -> (String,String,String) -> IO ExitCode+systemClustalw2 options (inputFilePath, outputFilePath, summaryFilePath) = system ("clustalw2 " ++ options ++ "-INFILE=" ++ inputFilePath ++ " -OUTFILE=" ++ outputFilePath ++ ">" ++ summaryFilePath)++-- | Run external clustalo command and return the Exitcode+systemClustalo :: String -> (String,String) -> IO ExitCode+systemClustalo options (inputFilePath, outputFilePath) = system ("clustalo " ++ options ++ "--infile=" ++ inputFilePath ++ " >" ++ outputFilePath)++-- | Run external CMbuild command and read the output into the corresponding datatype+systemCMbuild ::  String -> String -> String -> String -> IO ExitCode+systemCMbuild options alignmentFilepath modelFilepath outputFilePath = system ("cmbuild " ++ options ++ " " ++ modelFilepath ++ " " ++ alignmentFilepath  ++ " > " ++ outputFilePath)++-- | Run CMCompare and read the output into the corresponding datatype+systemCMcompare ::  String -> String -> String -> IO ExitCode+systemCMcompare model1path model2path outputFilePath = system ("CMCompare -q " ++ model1path ++ " " ++ model2path ++ " >" ++ outputFilePath)++-- | Run CMsearch+systemCMsearch :: Int -> String -> String -> String -> String -> IO ExitCode+systemCMsearch cpus options covarianceModelPath sequenceFilePath outputPath = system ("cmsearch --notrunc --cpu " ++ show cpus ++ " " ++ options ++ " -g " ++ covarianceModelPath ++ " " ++ sequenceFilePath ++ "> " ++ outputPath)++-- | Run CMstat+systemCMstat :: String -> String -> IO ExitCode+systemCMstat covarianceModelPath outputPath = system ("cmstat " ++ covarianceModelPath ++ " > " ++ outputPath)++-- | Run CMcalibrate and return exitcode+systemCMcalibrate :: String -> Int -> String -> String -> IO ExitCode+systemCMcalibrate mode cpus covarianceModelPath outputPath+  | mode == "fast" = system ("cmcalibrate --beta 1E-4 --cpu " ++ show cpus ++ " " ++ covarianceModelPath ++ "> " ++ outputPath)+  | otherwise = system ("cmcalibrate --cpu " ++ show cpus ++ " " ++ covarianceModelPath ++ "> " ++ outputPath)+++-- | Run CMcalibrate and return exitcode+systemCMalign :: String -> String -> String -> String -> IO ExitCode+systemCMalign options filePathCovarianceModel filePathSequence filePathAlignment = system ("cmalign " ++ options ++ " " ++ filePathCovarianceModel ++ " " ++ filePathSequence ++ "> " ++ filePathAlignment)++compareCM :: String -> String -> String -> IO (Either String Double)+compareCM rfamCMPath resultCMpath outputDirectory = do+  let myOptions = defaultDecodeOptions {+      decDelimiter = fromIntegral (ord ' ')+  }+  let rfamCMFileName = FP.takeBaseName rfamCMPath+  let resultCMFileName = FP.takeBaseName resultCMpath+  let cmcompareResultPath = outputDirectory ++ rfamCMFileName ++ resultCMFileName ++ ".cmcompare"+  _ <- systemCMcompare rfamCMPath resultCMpath cmcompareResultPath+  inputCMcompare <- readFile cmcompareResultPath+  let singlespaceCMcompare = unwords(words inputCMcompare)+  let decodedCmCompareOutput = head (V.toList (fromRight (decodeWith myOptions NoHeader (L.pack singlespaceCMcompare) :: Either String (V.Vector [String]))))+  --two.cm   three.cm     27.996     19.500 CCCAAAGGGCCCAAAGGG (((...)))(((...))) (((...)))(((...))) [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17] [11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27]+  let bitscore1 = read (decodedCmCompareOutput !! 2) :: Double+  let bitscore2 = read (decodedCmCompareOutput !! 3) :: Double+  let minmax = minimum [bitscore1,bitscore2]+  return (Right minmax)++readInt :: String -> Int+readInt = read++readDouble :: String -> Double+readDouble = read++extractCandidateSequences :: [(Fasta () (),Int,B.ByteString)] -> V.Vector (Int,Fasta () ())+extractCandidateSequences candidates' = indexedSeqences+  where sequences = map (\(inputSequence,_,_) -> inputSequence) candidates'+        indexedSeqences = V.map (\(number,inputSequence) -> (number + 1,inputSequence))(V.indexed (V.fromList sequences))++extractAlignedSequences :: Int -> ModelConstruction ->  V.Vector (Int,Fasta () ())+extractAlignedSequences iterationnumber modelconstruction+  | iterationnumber == 0 =  V.map (\(number,seq') -> (number + 1,seq')) (V.indexed (V.fromList inputSequence))+  | otherwise = indexedSeqRecords+  where inputSequence = inputFasta modelconstruction+        seqRecordsperTaxrecord = map sequenceRecords (taxRecords modelconstruction)+        seqRecords = concat seqRecordsperTaxrecord+        --alignedSeqRecords = filter (\seqRec -> (aligned seqRec) > 0) seqRecords+        indexedSeqRecords = V.map (\(number,seq') -> (number + 1,seq')) (V.indexed (V.fromList (inputSequence ++ map nucleotideSequence seqRecords)))++filterByParentTaxId :: [(J.Hit,Int)] -> Bool -> [(J.Hit,Int)]+filterByParentTaxId blastHitsWithParentTaxId singleHitPerParentTaxId+  |  singleHitPerParentTaxId = singleBlastHitperParentTaxId+  |  otherwise = blastHitsWithParentTaxId+  where blastHitsWithParentTaxIdSortedByParentTaxId = sortBy compareTaxId blastHitsWithParentTaxId+        blastHitsWithParentTaxIdGroupedByParentTaxId = groupBy sameTaxId blastHitsWithParentTaxIdSortedByParentTaxId+        singleBlastHitperParentTaxId = map (maximumBy compareHitEValue) blastHitsWithParentTaxIdGroupedByParentTaxId++filterByHitLength :: DS.Seq J.Hit -> Int -> Bool -> DS.Seq J.Hit+filterByHitLength blastHits queryLength filterOn+  | filterOn = filteredBlastHits+  | otherwise = blastHits+  where filteredBlastHits = DS.filter (hitLengthCheck queryLength) blastHits++-- | Hits should have a compareable length to query+hitLengthCheck :: Int -> J.Hit -> Bool+hitLengthCheck queryLength blastHit = lengthStatus+  where  hsps = J._hsps blastHit+         minHfrom = minimum (map J._hit_from hsps)+         minHfromHSP = fromJust (find (\hsp -> minHfrom == J._hit_from hsp) hsps)+         maxHto = maximum (map J._hit_to hsps)+         maxHtoHSP = fromJust (find (\hsp -> maxHto == J._hit_to hsp) hsps)+         minHonQuery = J._query_from minHfromHSP+         maxHonQuery = J._query_to maxHtoHSP+         startCoordinate = minHfrom - minHonQuery+         endCoordinate = maxHto + (queryLength - maxHonQuery)+         fullSeqLength = endCoordinate - startCoordinate+         lengthStatus = fullSeqLength < (queryLength * 3)++filterByCoverage :: DS.Seq J.Hit -> Int -> Bool -> DS.Seq J.Hit+filterByCoverage blastHits queryLength filterOn+  | filterOn = filteredBlastHits+  | otherwise = blastHits+  where filteredBlastHits = DS.filter (coverageCheck queryLength) blastHits++-- | Hits should have a compareable length to query+coverageCheck :: Int -> J.Hit -> Bool+coverageCheck queryLength hit = coverageStatus+  where  hsps = J._hsps hit+         maxIdentity = fromIntegral (maximum (map J._identity hsps))+         coverageStatus = (maxIdentity/fromIntegral queryLength)* (100 :: Double) >= (80 :: Double)++-- | Wrapper for retrieveFullSequence that rerequests incomplete return sequees+retrieveFullSequences :: StaticOptions -> [(String,Int,Int,String,T.Text,Int,B.ByteString)] -> IO [(Fasta () (),Int,B.ByteString)]+retrieveFullSequences staticOptions requestedSequences = do+  if offline staticOptions+    then do+      fullSequences <- mapM (retrieveFullSequenceBlastDb (fromJust (blastDatabase staticOptions)) (tempDirPath staticOptions)) requestedSequences+      if any (isNothing . firstOfTriple) fullSequences+       then do+         let fullSequencesWithRequestedSequences = zip fullSequences requestedSequences+         --let (failedRetrievals, successfulRetrievals) = partition (\x -> L.null (unSD (seqdata (firstOfTriple (fst x))))) fullSequencesWithRequestedSequences+         let (failedRetrievals, successfulRetrievals) = partition (isNothing . firstOfTriple . fst) fullSequencesWithRequestedSequences+         --we try to reretrieve failed entries once+         missingSequences <- mapM (retrieveFullSequence (tempDirPath staticOptions) .snd) failedRetrievals+         let (stillMissingSequences,reRetrievedSequences) = partition (isNothing . firstOfTriple) missingSequences+         logWarning ("Sequence retrieval failed: \n" ++ concatMap show stillMissingSequences ++ "\n") (tempDirPath staticOptions)+         let unwrappedRetrievals = map (\(x,y,z) -> (fromJust x,y,z))  (map fst successfulRetrievals ++ reRetrievedSequences)+         CE.evaluate unwrappedRetrievals+       else CE.evaluate (map (\(x,y,z) -> (fromJust x,y,z)) fullSequences)+    else do+     fullSequences <- mapM (retrieveFullSequence (tempDirPath staticOptions)) requestedSequences+     if any (isNothing . firstOfTriple) fullSequences+       then do+         let fullSequencesWithRequestedSequences = zip fullSequences requestedSequences+         --let (failedRetrievals, successfulRetrievals) = partition (\x -> L.null (unSD (seqdata (firstOfTriple (fst x))))) fullSequencesWithRequestedSequences+         let (failedRetrievals, successfulRetrievals) = partition (isNothing . firstOfTriple . fst) fullSequencesWithRequestedSequences+         --we try to reretrieve failed entries once+         missingSequences <- mapM (retrieveFullSequence (tempDirPath staticOptions) .snd) failedRetrievals+         let (stillMissingSequences,reRetrievedSequences) = partition (isNothing . firstOfTriple) missingSequences+         logWarning ("Sequence retrieval failed: \n" ++ concatMap show stillMissingSequences ++ "\n") (tempDirPath staticOptions)+         let unwrappedRetrievals = map (\(x,y,z) -> (fromJust x,y,z))  (map fst successfulRetrievals ++ reRetrievedSequences)+         CE.evaluate unwrappedRetrievals+       else CE.evaluate (map (\(x,y,z) -> (fromJust x,y,z)) fullSequences)++--retrieveFullSequenceBlastDb = retrieveFullSequence+retrieveFullSequenceBlastDb :: String -> String -> (String,Int,Int,String,T.Text,Int,B.ByteString) -> IO (Maybe (Fasta () ()),Int,B.ByteString)+retrieveFullSequenceBlastDb blastDb temporaryDirectoryPath (nucleotideId,seqStart,seqStop,strand,_,taxid,subject') = do+  let sequencePath = temporaryDirectoryPath ++ "/" ++ nucleotideId ++ ".fa"+  let cmd = "blastdbcmd -db " ++ blastDb ++ " -range " ++ (show seqStart) ++ "-" ++ (show seqStop) ++ " -strand " ++ (setBlastDbStrand strand) ++ " -entry " ++ nucleotideId ++ " -outfmt %f -target_only -out " ++ sequencePath+  print cmd+  system(cmd)  +  retrievedSequence <- readFastaFile sequencePath+  if null retrievedSequence+    then return(Nothing,taxid,subject')+    else do+      let justSequence = Just . head $ retrievedSequence+      return(justSequence,taxid,subject')  ++setBlastDbStrand :: String -> String+setBlastDbStrand strand+  | strand == "2" = "minus"+  | strand == "1" = "plus"+  | otherwise = "plus"+          +retrieveFullSequence :: String -> (String,Int,Int,String,T.Text,Int,B.ByteString) -> IO (Maybe (Fasta () ()),Int,B.ByteString)+retrieveFullSequence temporaryDirectoryPath (nucleotideId,seqStart,seqStop,strand,_,taxid,subject') = do+  let program' = Just "efetch"+  let database' = Just "nucleotide"+  let registrationInfo = buildRegistration "RNAlien" "florian.eggenhofer@univie.ac.at"+  let queryString = "id=" ++ nucleotideId ++ "&seq_start=" ++ show seqStart ++ "&seq_stop=" ++ show seqStop ++ "&rettype=fasta" ++ "&strand=" ++ strand ++ registrationInfo+  let entrezQuery = EntrezHTTPQuery program' database' queryString+  result <- CE.catch (entrezHTTP entrezQuery)+              (\e -> do let err = show (e :: CE.IOException)+                        logWarning ("Warning: Full sequence retrieval failed:" ++ " " ++ err) temporaryDirectoryPath+                        return [])+  if null result+    then return (Nothing,taxid,subject')+    else do+      --let parsedFastas = (BFS.parseFasta (L.pack result))+      let parsedFastas = byteStringToMultiFasta (L.pack result)+      if (null parsedFastas)+        then return (Nothing,taxid,subject')+        else do+          let parsedFasta = head parsedFastas+          if null (B.unpack . _bioSequence . _fasta $ parsedFasta)+            then return (Nothing,taxid,subject')+            else CE.evaluate (Just parsedFasta,taxid,subject')++getRequestedSequenceElement :: Int -> (J.Hit,Int) -> (String,Int,Int,String,T.Text,Int,B.ByteString)+getRequestedSequenceElement queryLength (blastHit,taxid)+  | blastHitIsReverseComplement (blastHit,taxid) = getReverseRequestedSequenceElement queryLength (blastHit,taxid)+  | otherwise = getForwardRequestedSequenceElement queryLength (blastHit,taxid)++blastHitIsReverseComplement :: (J.Hit,Int) -> Bool+blastHitIsReverseComplement (blastHit,_) = isReverse+  where blastMatch = head (J._hsps blastHit)+        firstHSPfrom = J._hit_from blastMatch+        firstHSPto = J._hit_to blastMatch+        isReverse = firstHSPfrom > firstHSPto++getForwardRequestedSequenceElement :: Int -> (J.Hit,Int) -> (String,Int,Int,String,T.Text,Int,B.ByteString)+getForwardRequestedSequenceElement queryLength (blastHit,taxid) = (geneIdentifier',startcoordinate,endcoordinate,strand,accession',taxid,subjectBlast)+   where    accession' = J._accession . head . J._description $ blastHit+            subjectBlast = E.encodeUtf8 . J._title . head . J._description $ blastHit+            geneIdentifier' = extractGeneId blastHit+            blastMatch = head (J._hsps blastHit)+            blastHitOriginSequenceLength = J._len blastHit+            minHfrom = J._hit_from blastMatch+            maxHto = J._hit_to blastMatch+            minHonQuery = J._query_from blastMatch+            maxHonQuery = J._query_to blastMatch+            --unsafe coordinates may exceed length of available sequence+            unsafestartcoordinate = minHfrom - minHonQuery+            unsafeendcoordinate = maxHto + (queryLength - maxHonQuery)+            startcoordinate = lowerBoundryCoordinateSetter 0 unsafestartcoordinate+            endcoordinate = upperBoundryCoordinateSetter blastHitOriginSequenceLength unsafeendcoordinate+            strand = "1"+            ----+            --blastMatches = matches blastHit+            --blastHitOriginSequenceLength = slength blastHit+            --minHfrom = minimum (map h_from blastMatches)+            --minHfromHSP = fromJust (find (\hsp -> minHfrom == h_from hsp) blastMatches)+            --maxHto = maximum (map h_to blastMatches)+            --maxHtoHSP = fromJust (find (\hsp -> maxHto == h_to hsp) blastMatches)+            --minHonQuery = q_from minHfromHSP+            --maxHonQuery = q_to maxHtoHSP+            --unsafe coordinates may exceed length of available sequence+            --unsafestartcoordinate = minHfrom - minHonQuery+            --unsafeendcoordinate = maxHto + (queryLength - maxHonQuery)+            --startcoordinate = lowerBoundryCoordinateSetter 0 unsafestartcoordinate+            --endcoordinate = upperBoundryCoordinateSetter blastHitOriginSequenceLength unsafeendcoordinate+            --strand = "1"++lowerBoundryCoordinateSetter :: Int -> Int -> Int+lowerBoundryCoordinateSetter lowerBoundry currentValue+  | currentValue < lowerBoundry = lowerBoundry+  | otherwise = currentValue++upperBoundryCoordinateSetter :: Int -> Int -> Int+upperBoundryCoordinateSetter upperBoundry currentValue+  | currentValue > upperBoundry = upperBoundry+  | otherwise = currentValue++getReverseRequestedSequenceElement :: Int -> (J.Hit,Int) -> (String,Int,Int,String,T.Text,Int,B.ByteString)+getReverseRequestedSequenceElement queryLength (blastHit,taxid) = (geneIdentifier',startcoordinate,endcoordinate,strand,accession',taxid,subjectBlast)+   where   accession' = J._accession . head . J._description $ blastHit+           subjectBlast = E.encodeUtf8 . J._title . head . J._description $ blastHit+           geneIdentifier' = extractGeneId blastHit+           blastMatch = head (J._hsps blastHit)+           blastHitOriginSequenceLength = J._len blastHit+           maxHfrom = J._hit_from blastMatch+           minHto = J._hit_to blastMatch+           minHonQuery = J._query_from blastMatch+           maxHonQuery = J._query_to blastMatch+           --unsafe coordinates may exceed length of avialable sequence+           unsafestartcoordinate = maxHfrom + minHonQuery+           unsafeendcoordinate = minHto - (queryLength - maxHonQuery)+           startcoordinate = lowerBoundryCoordinateSetter 0 unsafeendcoordinate+           endcoordinate = upperBoundryCoordinateSetter blastHitOriginSequenceLength unsafestartcoordinate+           strand = "2"+           --+           --blastMatches = matches blastHit+           --blastHitOriginSequenceLength = slength blastHit+           --maxHfrom = maximum (map h_from blastMatches)+           --maxHfromHSP = fromJust (find (\hsp -> maxHfrom == h_from hsp) blastMatches)+           --minHto = minimum (map h_to blastMatches)+           --minHtoHSP = fromJust (find (\hsp -> minHto == h_to hsp) blastMatches)+           --minHonQuery = q_from maxHfromHSP+           --maxHonQuery = q_to minHtoHSP+           --unsafe coordinates may exeed length of avialable sequence+           --unsafestartcoordinate = maxHfrom + minHonQuery+           --unsafeendcoordinate = minHto - (queryLength - maxHonQuery)+           --startcoordinate = lowerBoundryCoordinateSetter 0 unsafeendcoordinate+           --endcoordinate = upperBoundryCoordinateSetter blastHitOriginSequenceLength unsafestartcoordinate+           --strand = "2"++--computeAlignmentSCIs :: [String] -> [String] -> IO ()+--computeAlignmentSCIs alignmentFilepaths rnazOutputFilepaths = do+--  let zippedFilepaths = zip alignmentFilepaths rnazOutputFilepaths+--  mapM_ systemRNAz zippedFilepaths++alignSequences :: String -> String -> [String] -> [String] -> [String] -> [String] -> IO ()+alignSequences program' options fastaFilepaths fastaFilepaths2 alignmentFilepaths summaryFilepaths = do+  let zipped4Filepaths = zip4 fastaFilepaths fastaFilepaths2 alignmentFilepaths summaryFilepaths+  let zipped3Filepaths = zip3 fastaFilepaths alignmentFilepaths summaryFilepaths+  let zippedFilepaths = zip fastaFilepaths alignmentFilepaths+  let timeout = "3600"+  case program' of+    "locarna" -> mapM_ (systemlocarna options) zipped4Filepaths+    "mlocarna" -> mapM_ (systemMlocarna options) zippedFilepaths+    "mlocarnatimeout" -> mapM_ (systemMlocarnaWithTimeout timeout options) zippedFilepaths+    "clustalo" -> mapM_ (systemClustalo options) zippedFilepaths+    _ -> mapM_ (systemClustalw2 options ) zipped3Filepaths++constructFastaFilePaths :: String -> (Int, Fasta () ()) -> String+constructFastaFilePaths currentDirectory (fastaIdentifier, _) = currentDirectory ++ show fastaIdentifier ++".fa"++constructCMsearchFilePaths :: String -> (Int, Fasta () ()) -> String+constructCMsearchFilePaths currentDirectory (fastaIdentifier, _) = currentDirectory ++ show fastaIdentifier ++".cmsearch"++-- Smaller e-Values are greater, the maximum function is applied+compareHitEValue :: (J.Hit,Int) -> (J.Hit,Int) -> Ordering+compareHitEValue (hit1,_) (hit2,_)+  | hitEValue hit1 > hitEValue hit2 = LT+  | hitEValue hit1 < hitEValue hit2 = GT+  -- in case of equal evalues the first hit is selected+  | hitEValue hit1 == hitEValue hit2 = GT+-- comparing (hitEValue . Down . fst)+compareHitEValue (_,_) (_,_) = EQ++compareTaxId :: (J.Hit,Int) -> (J.Hit,Int) -> Ordering+compareTaxId (_,taxId1) (_,taxId2)+  | taxId1 > taxId2 = LT+  | taxId1 < taxId2 = GT+  -- in case of equal evalues the first hit is selected+  | taxId1 == taxId2 = EQ+compareTaxId (_,_)  (_,_) = EQ++sameTaxId :: (J.Hit,Int) -> (J.Hit,Int) -> Bool+sameTaxId (_,taxId1) (_,taxId2) = taxId1 == taxId2++-- | NCBI uses the e-Value of the best HSP as the Hits e-Value+hitEValue :: J.Hit -> Double+hitEValue currentHit = minimum (map J._evalue (J._hsps currentHit))++convertFastaFoldStockholm :: Fasta () () -> String -> String+convertFastaFoldStockholm fastasequence foldedStructure = stockholmOutput+  where alnHeader = "# STOCKHOLM 1.0\n\n"+        --(L.unpack (fastaHeader inputFasta'))) ++ "\n" ++ (map toUpper (L.unpack (fastaSequence inputFasta'))) ++ "\n"+        seqIdentifier = B.unpack . _sequenceIdentifier . _header $fastasequence+        seqSequence = B.unpack . _bioSequence . _fasta $ fastasequence+        identifierLength = length seqIdentifier+        spacerLength' = maximum [14,identifierLength + 2]+        spacer = replicate (spacerLength' - identifierLength) ' '+        entrystring = seqIdentifier ++ spacer ++ seqSequence ++ "\n"+        structureString = "#=GC SS_cons" ++ replicate (spacerLength' - 12) ' ' ++ foldedStructure ++ "\n"+        bottom = "//"+        stockholmOutput = alnHeader ++ entrystring ++ structureString ++ bottom++convertClustaltoStockholm :: StructuralClustalAlignment -> T.Text+convertClustaltoStockholm parsedMlocarnaAlignment = stockholmOutput+  where alnHeader = T.pack "# STOCKHOLM 1.0\n\n"+        clustalAlignment = structuralAlignmentEntries parsedMlocarnaAlignment+        uniqueIds = nub (map entrySequenceIdentifier clustalAlignment)+        mergedEntries = map (mergeEntry clustalAlignment) uniqueIds+        maxIdentifierLenght = maximum (map (T.length . entrySequenceIdentifier) clustalAlignment)+        spacerLength' = maxIdentifierLenght + 2+        stockholmEntries = T.concat (map (buildStockholmAlignmentEntries spacerLength') mergedEntries)+        structureString = T.pack "#=GC SS_cons" `T.append` T.replicate (spacerLength' - 12) (T.pack " ")  `T.append` secondaryStructureTrack parsedMlocarnaAlignment `T.append` T.pack "\n"+        bottom = T.pack "//"+        stockholmOutput = alnHeader `T.append` stockholmEntries `T.append` structureString `T.append` bottom++mergeEntry :: [ClustalAlignmentEntry] -> T.Text -> ClustalAlignmentEntry+mergeEntry clustalAlignment uniqueId = mergedEntry+  where idEntries = filter (\entry -> entrySequenceIdentifier entry==uniqueId) clustalAlignment+        mergedSeq = foldr (T.append . entryAlignedSequence) (T.pack "") idEntries+        mergedEntry = ClustalAlignmentEntry uniqueId mergedSeq++buildStockholmAlignmentEntries :: Int -> ClustalAlignmentEntry -> T.Text+buildStockholmAlignmentEntries inputSpacerLength entry = entrystring+  where idLength = T.length (T.filter (/= '\n') (entrySequenceIdentifier entry))+        spacer = T.replicate (inputSpacerLength - idLength) (T.pack " ")+        entrystring = entrySequenceIdentifier entry `T.append` spacer `T.append` entryAlignedSequence entry `T.append` T.pack "\n"++retrieveTaxonomicContextEntrez :: Int -> IO (Maybe Taxon)+retrieveTaxonomicContextEntrez inputTaxId = do+       let program' = Just "efetch"+       let database' = Just "taxonomy"+       let taxIdString = show inputTaxId+       let registrationInfo = buildRegistration "RNAlien" "florian.eggenhofer@univie.ac.at"+       let queryString = "id=" ++ taxIdString ++ registrationInfo+       let entrezQuery = EntrezHTTPQuery program' database' queryString+       result <- entrezHTTP entrezQuery+       if null result+          then do+            error "Could not retrieve taxonomic context from NCBI Entrez, cannot proceed."+            return Nothing+          else do+            let taxon = head (readEntrezTaxonSet result)+            --print taxon+            if null (lineageEx taxon)+              then error "Retrieved taxonomic context taxon from NCBI Entrez with empty lineage, cannot proceed."+              else return (Just taxon)++retrieveParentTaxIdEntrez :: [(J.Hit,Int)] -> IO [(J.Hit,Int)]+retrieveParentTaxIdEntrez blastHitsWithHitTaxids =+  if not (null blastHitsWithHitTaxids)+     then do+       let program' = Just "efetch"+       let database' = Just "taxonomy"+       let extractedBlastHits = map fst blastHitsWithHitTaxids+       let taxIds = map snd blastHitsWithHitTaxids+       let taxIdStrings = map show taxIds+       let taxIdQuery = intercalate "," taxIdStrings+       let registrationInfo = buildRegistration "RNAlien" "florian.eggenhofer@univie.ac.at"+       let queryString = "id=" ++ taxIdQuery ++ registrationInfo+       let entrezQuery = EntrezHTTPQuery program' database' queryString+       result <- entrezHTTP entrezQuery+       let parentTaxIds = readEntrezParentIds result+       if null parentTaxIds+         then return []+         else CE.evaluate (zip extractedBlastHits parentTaxIds)+    else return []++-- | Wrapper functions that ensures that only 20 queries are sent per request+retrieveParentTaxIdsEntrez :: [(J.Hit,Int)] -> IO [(J.Hit,Int)]+retrieveParentTaxIdsEntrez taxIdwithBlastHits = do+  let splits = portionListElements taxIdwithBlastHits 20+  taxIdsOutput <- mapM retrieveParentTaxIdEntrez splits+  return (concat taxIdsOutput)++-- | Extract taxids from JSON2 blasthit+extractBlastHitsTaxId :: DS.Seq J.Hit -> [(J.Hit,Int)]+extractBlastHitsTaxId blastHits = do+  map (\a -> (a,J._taxid . head . J._description $ a)) (Data.Foldable.toList blastHits)+++-- | Wrapper functions that ensures that only 20 queries are sent per request+--retrieveBlastHitsTaxIdEntrez :: [J.Hit] -> IO [([J.Hit],String)]+--retrieveBlastHitsTaxIdEntrez blastHits = do+--  let splits = portionListElements blastHits 20+--  mapM retrieveBlastHitTaxIdEntrez splits+++retrieveBlastHitTaxIdEntrez :: [J.Hit] -> IO ([J.Hit],String)+retrieveBlastHitTaxIdEntrez blastHits =+  if not (null blastHits)+     then do+       let geneIds = map extractGeneId blastHits+       let idList = intercalate "," geneIds+       let registrationInfo = buildRegistration "RNAlien" "florian.eggenhofer@univie.ac.at"+       let query' = "id=" ++ idList ++ registrationInfo+       let entrezQuery = EntrezHTTPQuery (Just "esummary") (Just "nucleotide") query'+       threadDelay 10000000+       result <- entrezHTTP entrezQuery+       CE.evaluate (blastHits,result)+     else return (blastHits,"")++extractTaxIdFromEntrySummaries :: String -> [Int]+extractTaxIdFromEntrySummaries input+  | null input = []+  | null parsedResultList = []+  | otherwise = hitTaxIds+  where parsedResultList = readEntrezSummaries input+        parsedResult = head parsedResultList+        blastHitSummaries = documentSummaries parsedResult+        hitTaxIdStrings = map extractTaxIdfromDocumentSummary blastHitSummaries+        hitTaxIds = map readInt hitTaxIdStrings++extractGeneId :: J.Hit -> String+extractGeneId currentBlastHit = nucleotideId+  where truncatedId = drop 3 (T.unpack (J._id (head (J._description currentBlastHit))))+        pipeSymbolIndex = fromJust (elemIndex '|' truncatedId)+        nucleotideId = take pipeSymbolIndex truncatedId++extractTaxIdfromDocumentSummary :: EntrezDocSum -> String+extractTaxIdfromDocumentSummary documentSummary = itemContent (fromJust (find (\item -> "TaxId" == itemName item) (summaryItems documentSummary)))++getBestHit :: J.BlastJSON2 -> J.Hit+getBestHit blastJS2+  | null (J._hits (J._search . J._results . J._report . J._blastoutput2 $ blastJS2)) = error "getBestHit - head: empty list"+  | otherwise = DS.index (J._hits (J._search . J._results . J._report . J._blastoutput2 $ blastJS2)) 1++-- Blast returns low evalues with zero instead of the exact number+getHitWithFractionEvalue :: J.BlastJSON2 -> Maybe J.Hsp+getHitWithFractionEvalue blastJS2+  | null currentHits = Nothing+  | otherwise = find (\hsp -> J._evalue hsp /= (0 ::Double)) (concatMap J._hsps currentHits)+  where currentHits = J._hits . J._search . J._results . J._report . J._blastoutput2 $ blastJS2++showlines :: (Show a, Foldable t) => t a -> String+showlines = concatMap (\x -> show x ++ "\n")++logMessage :: String -> String -> IO ()+logMessage logoutput temporaryDirectoryPath = appendFile (temporaryDirectoryPath ++ "Log") logoutput++logWarning :: String -> String -> IO ()+logWarning logoutput temporaryDirectoryPath = appendFile (temporaryDirectoryPath ++ "log/warnings") logoutput++logVerboseMessage :: Bool -> String -> String -> IO ()+logVerboseMessage verboseTrue logoutput temporaryDirectoryPath+  | verboseTrue = appendFile (temporaryDirectoryPath ++ "Log") (show logoutput)+  | otherwise = return ()++logEither :: (Show a) => Either a b -> String -> IO ()+logEither (Left logoutput) temporaryDirectoryPath = appendFile (temporaryDirectoryPath ++ "Log") (show logoutput)+logEither  _ _ = return ()++checkTools :: [String] -> String -> String -> IO (Either String String)+checkTools tools temporaryDirectoryPath selectedQuerySelectionMethod = do+  -- if queryselectionmethod is set to clustering then also check for clustal omega+  let additionaltools = if selectedQuerySelectionMethod == "clustering" then tools ++ ["clustalo"] else tools+  -- check if all tools are available via PATH or Left+  checks <- mapM checkTool additionaltools+  if not (null (lefts checks))+    then return (Left (concat (lefts checks)))+    else do+      logMessage ("Tools : " ++ intercalate "," tools ++ "\n") temporaryDirectoryPath+      return (Right "Tools ok")++logToolVersions :: String -> String -> IO ()+logToolVersions inputQuerySelectionMethod temporaryDirectoryPath = do+  let clustaloversionpath = temporaryDirectoryPath ++ "log/clustalo.version"+  let mlocarnaversionpath = temporaryDirectoryPath ++ "log/mlocarna.version"+  let rnafoldversionpath = temporaryDirectoryPath ++ "log/RNAfold.version"+  let infernalversionpath = temporaryDirectoryPath ++ "log/Infernal.version"+  --_ <- system ("clustalo --version >" ++ clustaloversionpath)+  _ <- system ("mlocarna --version >" ++ mlocarnaversionpath)+  _ <- system ("RNAfold --version >" ++ rnafoldversionpath)+  _ <- system ("cmcalibrate -h >" ++ infernalversionpath)+  -- _ <- system ("RNAz" ++ rnazversionpath)+  -- _ <- system ("CMCompare >" ++ infernalversionpath)+  mlocarnaversion <- readFile mlocarnaversionpath+  rnafoldversion <- readFile rnafoldversionpath+  infernalversionOutput <- readFile infernalversionpath+  let infernalversion = lines infernalversionOutput !! 1+  if inputQuerySelectionMethod == "clustering"+     then do+       _ <- system ("clustalo --version >" ++ clustaloversionpath)+       clustaloversion <- readFile clustaloversionpath+       let messageString = "Clustalo version: " ++ clustaloversion ++ "mlocarna version: " ++ mlocarnaversion  ++ "RNAfold version: " ++ rnafoldversion  ++ "infernalversion: " ++ infernalversion ++ "\n"+       logMessage messageString temporaryDirectoryPath+     else do+       let messageString = "mlocarna version: " ++ mlocarnaversion  ++ "RNAfold version: " ++ rnafoldversion  ++ "infernalversion: " ++ infernalversion ++ "\n"+       logMessage messageString temporaryDirectoryPath+++checkTool :: String -> IO (Either String String)+checkTool tool = do+  toolcheck <- findExecutable tool+  if isJust toolcheck+    then return (Right (fromJust toolcheck))+    else return (Left ("RNAlien could not find "++ tool ++ " in your $PATH and has to abort.\n"))++constructTaxonomyRecordsCSVTable :: ModelConstruction -> String+constructTaxonomyRecordsCSVTable modelconstruction = csvtable+  where tableheader = "Taxonomy Id;Added in Iteration Step;Entry Header\n"+        tablebody = concatMap constructTaxonomyRecordCSVEntries (taxRecords modelconstruction)+        csvtable = tableheader ++ tablebody++constructTaxonomyRecordCSVEntries :: TaxonomyRecord -> String+constructTaxonomyRecordCSVEntries taxRecord = concatMap (constructTaxonomyRecordCSVEntry taxIdString) (sequenceRecords taxRecord)+  where taxIdString = show (recordTaxonomyId taxRecord)++constructTaxonomyRecordCSVEntry :: String -> SequenceRecord -> String+constructTaxonomyRecordCSVEntry taxIdString seqrec = taxIdString ++ ";" ++ show (aligned seqrec) ++ ";" ++ filter checkTaxonomyRecordCSVChar (B.unpack (fastaHeader (nucleotideSequence seqrec))) ++ "\n"++checkTaxonomyRecordCSVChar :: Char -> Bool+checkTaxonomyRecordCSVChar c+  | c == '"' = False+  | c == ';' = False+  | otherwise = True++setVerbose :: Verbosity -> Bool+setVerbose verbosityLevel+  | verbosityLevel == Loud = True+  | otherwise = False++evaluateConstructionResult :: StaticOptions -> ModelConstruction -> IO String+evaluateConstructionResult staticOptions mCResult = do+  let evaluationDirectoryFilepath = tempDirPath staticOptions ++ "evaluation/"+  createDirectoryIfMissing False evaluationDirectoryFilepath+  let reformatedClustalPath = evaluationDirectoryFilepath ++ "result.clustal.reformated"+  let cmFilepath = tempDirPath staticOptions ++ "result.cm"+  let resultSequences = inputFasta mCResult ++ map nucleotideSequence (concatMap sequenceRecords (taxRecords mCResult))+  let resultNumber = length resultSequences+  let rnaCentralQueries = map RCH.buildSequenceViaMD5Query resultSequences+  rnaCentralEntries <- RCH.getRNACentralEntries rnaCentralQueries+  let rnaCentralEvaluationResult = RCH.showRNAcentralAlienEvaluation rnaCentralEntries+  writeFile (tempDirPath staticOptions ++ "result.rnacentral") rnaCentralEvaluationResult+  let resultModelStatistics = tempDirPath staticOptions ++ "result.cmstat"+  systemCMstat cmFilepath resultModelStatistics+  inputcmStat <- readCMstat resultModelStatistics+  let cmstatString = cmstatEvalOutput inputcmStat+  if resultNumber > 1+    then do+      let resultRNAz = tempDirPath staticOptions ++ "result.rnaz"+      let resultRNAcode = tempDirPath staticOptions ++ "result.rnacode"+      let resultClustalFilepath = tempDirPath staticOptions ++ "result.clustal"+      let seqNumber = 6 :: Int+      let optimalIdentity = 80 :: Double+      let maximalIdentity = 99 :: Double+      let referenceSequence = True+      preprocessingOutput <- preprocessClustalForRNAz resultClustalFilepath reformatedClustalPath seqNumber optimalIdentity maximalIdentity referenceSequence+      if isRight preprocessingOutput+        then do+          let rightPreprocessingOutput = fromRight preprocessingOutput+          let rnazClustalpath = snd rightPreprocessingOutput+          systemRNAz "-l" rnazClustalpath resultRNAz+          inputRNAz <- readRNAz resultRNAz+          let rnaZString = rnaZEvalOutput inputRNAz+          RC.systemRNAcode " -t " rnazClustalpath resultRNAcode+          inputRNAcode <- RC.readRNAcodeTabular resultRNAcode+          let rnaCodeString = rnaCodeEvalOutput inputRNAcode+          return ("\nEvaluation of RNAlien result :\nCMstat statistics for result.cm\n" ++ cmstatString ++ "\nRNAz statistics for result alignment: " ++ rnaZString ++ "\nRNAcode output for result alignment:\n" ++ rnaCodeString ++ "\nSequences found by RNAlien with RNAcentral entry:\n" ++ rnaCentralEvaluationResult)+        else do+          logWarning ("Running RNAz for result evalution encountered a problem:" ++ fromLeft preprocessingOutput) (tempDirPath staticOptions)+          return ("\nEvaluation of RNAlien result :\nCMstat statistics for result.cm\n" ++ cmstatString ++ "\nRNAz statistics for result alignment: Running RNAz for result evalution encountered a problem\n" ++ fromLeft preprocessingOutput ++ "\n" ++ "Sequences found by RNAlien with RNAcentral entry:\n" ++ rnaCentralEvaluationResult)+    else do+      logWarning "Message: RNAlien could not find additional covariant sequences\n Could not run RNAz statistics. Could not run RNAz statistics with a single sequence.\n" (tempDirPath staticOptions)+      return ("\nEvaluation of RNAlien result :\nCMstat statistics for result.cm\n" ++ cmstatString ++ "\nRNAlien could not find additional covariant sequences. Could not run RNAz statistics with a single sequence.\n\nSequences found by RNAlien with RNAcentral entry:\n" ++ rnaCentralEvaluationResult)+++cmstatEvalOutput :: Either ParseError CMstat -> String+cmstatEvalOutput inputcmstat+  | isRight inputcmstat = cmstatString+  | otherwise = show (fromLeft inputcmstat)+    where cmStat = fromRight inputcmstat+          cmstatString = "  Sequence Number: " ++ show (statSequenceNumber cmStat)++ "\n" ++ "  Effective Sequences: " ++ show (statEffectiveSequences cmStat)++ "\n" ++ "  Consensus length: " ++ show (statConsensusLength cmStat) ++ "\n" ++ "  Expected maximum hit-length: " ++ show (statW cmStat) ++ "\n" ++ "  Basepairs: " ++ show (statBasepairs cmStat)++ "\n" ++ "  Bifurcations: " ++ show (statBifurcations cmStat) ++ "\n" ++ "  Modeltype: " ++ show (statModel cmStat) ++ "\n" ++ "  Relative Entropy CM: " ++ show (relativeEntropyCM cmStat) ++ "\n" ++ "  Relative Entropy HMM: " ++ show (relativeEntropyHMM cmStat) ++ "\n"++rnaZEvalOutput :: Either ParseError RNAz -> String+rnaZEvalOutput inputRNAz+  | isRight inputRNAz = rnazString+  | otherwise = show (fromLeft inputRNAz)+    where rnaZ = fromRight inputRNAz+          rnazString = "  Mean pairwise identity: " ++ show (meanPairwiseIdentity rnaZ) ++ "\n  Shannon entropy: " ++ show (shannonEntropy rnaZ) ++  "\n  GC content: " ++ show (gcContent rnaZ) ++ "\n  Mean single sequence minimum free energy: " ++ show (meanSingleSequenceMinimumFreeEnergy rnaZ) ++ "\n  Consensus minimum free energy: " ++ show (consensusMinimumFreeEnergy rnaZ) ++ "\n  Energy contribution: " ++ show (energyContribution rnaZ) ++ "\n  Covariance contribution: " ++ show (covarianceContribution rnaZ) ++ "\n  Combinations pair: " ++ show (combinationsPair rnaZ) ++ "\n  Mean z-score: " ++ show (meanZScore rnaZ) ++ "\n  Structure conservation index: " ++ show (structureConservationIndex rnaZ) ++ "\n  Background model: " ++ backgroundModel rnaZ ++ "\n  Decision model: " ++ decisionModel rnaZ ++ "\n  SVM decision value: " ++ show (svmDecisionValue rnaZ) ++ "\n  SVM class propability: " ++ show (svmRNAClassProbability rnaZ) ++ "\n  Prediction: " ++ prediction rnaZ++rnaCodeEvalOutput :: Either ParseError RC.RNAcode -> String+rnaCodeEvalOutput inputRNAcode+  | isRight inputRNAcode = rnaCodeString+  | otherwise = show (fromLeft inputRNAcode)+    where rnaCode = fromRight inputRNAcode+          rnaCodeString = "HSS\tFrame\tLength\tFrom\tTo\tName\tStart\tEnd\tScore\tP\n" ++ rnaCodeEntries+          rnaCodeEntries = concatMap showRNACodeHits (RC.rnacodeHits rnaCode)++showRNACodeHits :: RC.RNAcodeHit -> String+showRNACodeHits rnacodeHit = show (RC.hss rnacodeHit) ++ "\t" ++ show (RC.frame rnacodeHit) ++ "\t" ++ show (RC.hitLength rnacodeHit) ++ "\t"++ show (RC.from rnacodeHit) ++ "\t" ++ show (RC.to rnacodeHit) ++ "\t" ++ RC.name rnacodeHit ++ "\t" ++ show (RC.start rnacodeHit) ++ "\t" ++ show (RC.end rnacodeHit) ++ "\t" ++ show (RC.score rnacodeHit) ++ show (RC.pvalue rnacodeHit) ++ "\n"++-- | Call for external preprocessClustalForRNAz+preprocessClustalForRNAzExternal :: String -> String -> Int -> Int -> Int -> Bool -> IO (Either String (String,String))+preprocessClustalForRNAzExternal clustalFilepath reformatedClustalPath seqenceNumber optimalIdentity maximalIdenity referenceSequence = do+  clustalText <- TI.readFile clustalFilepath+  --change clustal format for rnazSelectSeqs.pl+  let reformatedClustalText = T.map reformatAln clustalText+  TI.writeFile reformatedClustalPath reformatedClustalText+  --select representative entries from result.Clustal with select_sequences+  let selectedClustalpath = clustalFilepath ++ ".selected"+  let sequenceNumberOption = " -n "  ++ show seqenceNumber ++ " "+  let optimalIdentityOption = " -i "  ++ show optimalIdentity  ++ " "+  let maximalIdentityOption = " --max-id="  ++ show maximalIdenity  ++ " "+  let referenceSequenceOption = if referenceSequence then " " else " -x "+  let syscall = "rnazSelectSeqs.pl " ++ reformatedClustalPath ++ " " ++ sequenceNumberOption ++ optimalIdentityOption ++ maximalIdentityOption ++ referenceSequenceOption ++  " >" ++ selectedClustalpath+  --putStrLn syscall+  system syscall+  selectedClustalText <- readFile selectedClustalpath+  return (Right ([],selectedClustalText))++-- | Call for external preprocessClustalForRNAcode - RNAcode additionally to RNAz requirements does not accept pipe,underscore, doublepoint symbols+preprocessClustalForRNAcodeExternal :: String -> String -> Int -> Int -> Int -> Bool -> IO (Either String (String,String))+preprocessClustalForRNAcodeExternal clustalFilepath reformatedClustalPath seqenceNumber optimalIdentity maximalIdenity referenceSequence = do+  clustalText <- TI.readFile clustalFilepath+  --change clustal format for rnazSelectSeqs.pl+  let clustalTextLines = T.lines clustalText+  let headerClustalTextLines = T.unlines (take 2 clustalTextLines)+  let headerlessClustalTextLines = T.unlines (drop 2 clustalTextLines)+  let reformatedClustalText = T.map reformatRNACodeAln headerlessClustalTextLines+  TI.writeFile reformatedClustalPath (headerClustalTextLines `T.append` T.singleton '\n' `T.append` reformatedClustalText)+  --select representative entries from result.Clustal with select_sequences+  let selectedClustalpath = clustalFilepath ++ ".selected"+  let sequenceNumberOption = " -n "  ++ show seqenceNumber  ++ " "+  let optimalIdentityOption = " -i "  ++ show optimalIdentity  ++ " "+  let maximalIdentityOption = " --max-id="  ++ show maximalIdenity  ++ " "+  let referenceSequenceOption = if referenceSequence then " " else " -x "+  let syscall = "rnazSelectSeqs.pl " ++ reformatedClustalPath ++ " " ++ sequenceNumberOption ++ optimalIdentityOption ++ maximalIdentityOption ++ referenceSequenceOption ++  " >" ++ selectedClustalpath+  --putStrLn syscall+  system syscall+  selectedClustalText <- readFile selectedClustalpath+  return (Right ([],selectedClustalText))++preprocessClustalForRNAz :: String -> String -> Int -> Double -> Double -> Bool -> IO (Either String (String,String))+preprocessClustalForRNAz clustalFilepath _ seqenceNumber optimalIdentity maximalIdenity referenceSequence = do+  clustalText <- TI.readFile clustalFilepath+  let clustalTextLines = T.lines clustalText+  parsedClustalInput <- readClustalAlignment clustalFilepath+  let selectedClustalpath = clustalFilepath ++ ".selected"+  if length clustalTextLines > 5+    then+      if isRight parsedClustalInput+        then do+          let (idMatrix,filteredClustalInput) = rnaCodeSelectSeqs2 (fromRight parsedClustalInput) seqenceNumber optimalIdentity maximalIdenity referenceSequence+          writeFile selectedClustalpath (show filteredClustalInput)+          let formatedIdMatrix = show (fmap formatIdMatrix idMatrix)+          return (Right (formatedIdMatrix,selectedClustalpath))+        else return (Left (show (fromLeft parsedClustalInput)))+    else do+      let clustalLines = T.lines clustalText+      let headerClustalTextLines = T.unlines (take 2 clustalLines)+      let headerlessClustalTextLines = T.unlines (drop 2 clustalLines)+      let reformatedClustalText = T.map reformatRNACodeAln headerlessClustalTextLines+      TI.writeFile selectedClustalpath (headerClustalTextLines `T.append` T.singleton '\n' `T.append` reformatedClustalText)+      return (Right ([],clustalFilepath))++formatIdMatrix :: Maybe (Int,Int,Double) -> String+formatIdMatrix (Just (_,_,c)) = printf "%.2f" c+formatIdMatrix _ = "-"+++-- | Sequence preselection for RNAz and RNAcode+rnaCodeSelectSeqs2 :: ClustalAlignment -> Int -> Double -> Double -> Bool -> (Matrix (Maybe (Int,Int,Double)),ClustalAlignment)+rnaCodeSelectSeqs2 currentClustalAlignment targetSeqNumber optimalIdentity maximalIdentity referenceSequence = (identityMatrix,newClustalAlignment)+  where entryVector = V.fromList (alignmentEntries currentClustalAlignment)+        entrySequences = V.map entryAlignedSequence entryVector+        entryReformatedSequences = V.map (T.map reformatRNACodeAln) entrySequences+        totalSeqNumber = V.length entryVector+        identityMatrix = computeSequenceIdentityMatrix entryReformatedSequences+        entryIdentityVector = V.map fromJust (V.filter isJust (getMatrixAsVector identityMatrix))+        entryIdentities = V.toList entryIdentityVector+        --Similarity filter - filter too similar sequences until alive seqs are less then minSeqs+        entriesToDiscard = preFilterIdentityMatrix maximalIdentity targetSeqNumber totalSeqNumber [] entryIdentities+        allEntries = [1..totalSeqNumber]+        prefilteredEntries = allEntries \\ entriesToDiscard+        --Optimize mean pairwise similarity (greedily) - remove worst sequence until desired number is reached+        costList = map (computeEntryCost optimalIdentity entryIdentityVector) prefilteredEntries+        sortedCostList = sortBy compareEntryCost2 costList+        sortedIndices = map fst sortedCostList+        --selectedEntryIndices = [1] ++ map fst (take (targetSeqNumber -1) sortedCostList)+        selectedEntryIndices = selectEntryIndices referenceSequence targetSeqNumber sortedIndices+        selectedEntries = map (\ind -> entryVector V.! (ind-1)) selectedEntryIndices+        selectedEntryHeader = map entrySequenceIdentifier selectedEntries+        reformatedSelectedEntryHeader =  map (T.map reformatRNACodeId) selectedEntryHeader+        selectedEntrySequences = map (\ind -> entryReformatedSequences V.! (ind-1)) selectedEntryIndices+        --gapfreeEntrySequences = T.transpose (T.filter (\a -> not (T.all isGap a)) (T.transpose selectedEntrySequences))+        gapfreeEntrySequences = T.transpose (filter (not . T.all isGap) (T.transpose selectedEntrySequences))+        gapfreeEntries = map (uncurry ClustalAlignmentEntry)(zip reformatedSelectedEntryHeader gapfreeEntrySequences)+        emptyConservationTrack = setEmptyConservationTrack gapfreeEntries (conservationTrack currentClustalAlignment)+        newClustalAlignment = currentClustalAlignment {alignmentEntries = gapfreeEntries, conservationTrack = emptyConservationTrack}++selectEntryIndices :: Bool -> Int -> [Int] -> [Int]+selectEntryIndices referenceSequence targetSeqNumber sortedIndices+  | referenceSequence = if (1 :: Int) `elem` firstX then firstX else 1:firstXm1+  | otherwise = firstX+    where firstXm1 = take (targetSeqNumber - 1)  sortedIndices+          firstX = take targetSeqNumber sortedIndices++setEmptyConservationTrack :: [ClustalAlignmentEntry] -> T.Text -> T.Text+setEmptyConservationTrack alnentries currentConservationTrack+  | null alnentries = currentConservationTrack+  | otherwise = newConservationTrack+      where trackLength = T.length (entryAlignedSequence (head alnentries))+            newConservationTrack = T.replicate (trackLength + 0) (T.pack " ")++isGap :: Char -> Bool+isGap a+  | a == '-' = True+  | otherwise = False++computeEntryCost :: Double -> V.Vector (Int,Int,Double) -> Int -> (Int,Double)+computeEntryCost optimalIdentity allIdentities currentIndex = (currentIndex,entryCost)+  where entryCost = V.sum (V.map (computeCost optimalIdentity) entryIdentities)+        entryIdentities = getEntryIdentities currentIndex allIdentities++getEntryIdentities :: Int -> V.Vector (Int,Int,Double) -> V.Vector (Int,Int,Double)+getEntryIdentities currentIndex allIdentities = V.filter (isIIdx currentIndex) allIdentities V.++ V.filter (isJIdx currentIndex) allIdentities++isIIdx :: Int -> (Int,Int,Double) -> Bool+isIIdx currentIdx (i,_,_) = currentIdx == i+isJIdx :: Int -> (Int,Int,Double) -> Bool+isJIdx currentIdx (_,j,_) = currentIdx == j++computeCost :: Double -> (Int,Int,Double) -> Double+computeCost optimalIdentity (_,_,c) = (c - optimalIdentity) * (c - optimalIdentity)++compareEntryCost2 :: (Int, Double) -> (Int, Double) -> Ordering+compareEntryCost2 (_,costA) (_,costB) = compare costA costB++-- TODO change to vector+preFilterIdentityMatrix :: Double -> Int -> Int-> [Int] -> [(Int,Int,Double)] -> [Int]+preFilterIdentityMatrix identityCutoff minSeqNumber totalSeqNumber filteredIds entryIdentities+    | (totalSeqNumber - length filteredIds) <= minSeqNumber = []+    | identityCutoff == (100 :: Double) = []+    | Prelude.null entryIdentities  = []+    | otherwise = entryresult ++ preFilterIdentityMatrix identityCutoff minSeqNumber totalSeqNumber (filteredIds ++ entryresult) (tail entryIdentities)+      where currentEntry = head entryIdentities+            entryresult = checkIdentityEntry identityCutoff filteredIds currentEntry++checkIdentityEntry :: Double -> [Int] -> (Int,Int,Double) -> [Int]+checkIdentityEntry identityCutoff filteredIds (i,j,ident)+  | i `elem` filteredIds = []+  | j `elem` filteredIds = []+  | ident > identityCutoff = [j]+  | otherwise = []++computeSequenceIdentityMatrix :: V.Vector T.Text -> Matrix (Maybe (Int,Int,Double))+computeSequenceIdentityMatrix entryVector = matrix (V.length entryVector) (V.length entryVector) (computeSequenceIdentityEntry entryVector)++-- Computes Sequence identity once for each pair and not vs itself+computeSequenceIdentityEntry :: V.Vector T.Text -> (Int,Int) -> Maybe (Int,Int,Double)+computeSequenceIdentityEntry entryVector (row,col)+  | i < j = Just (row,col,ident)+  | otherwise = Nothing+  where i=row-1+        j=col-1+        --gaps in both sequences need to be removed, because they count as match+        ientry  = entryVector V.! i+        jentry = entryVector V.! j+        (gfi,gfj) = unzip (filter notDoubleGap (T.zip ientry jentry))+        gfitext = T.pack gfi+        gfjtext = T.pack gfj+        --ident=stringIdentity gfi gfj+        ident=textIdentity gfitext gfjtext++notDoubleGap :: (Char,Char) -> Bool+notDoubleGap (a,b)+  | a == '-' && b == '-' = False+  | otherwise = True++reformatRNACodeId :: Char -> Char+reformatRNACodeId c+  | c == ':' = '-'+  | c == '|' = '-'+  | c == '.' = '-'+  | c == '~' = '-'+  | c == '_' = '-'+  | c == '/' = '-'+  | otherwise = c++reformatRNACodeAln :: Char -> Char+reformatRNACodeAln c+  | c == ':' = '-'+  | c == '|' = '-'+  | c == '.' = '-'+  | c == '~' = '-'+  | c == '_' = '-'+  | c == 'u' = 'U'+  | c == 't' = 'T'+  | c == 'g' = 'G'+  | c == 'c' = 'C'+  | c == 'a' = 'A'+  | otherwise = c++reformatAln :: Char -> Char+reformatAln c+  | c == '.' = '-'+  | c == '~' = '-'+  | c == '_' = '-'+  | c == 'u' = 'U'+  | c == 't' = 'T'+  | c == 'g' = 'G'+  | c == 'c' = 'C'+  | c == 'a' = 'A'+  | otherwise = c++-- | Check if alien can connect to NCBI+checkNCBIConnection :: IO (Either String String)+checkNCBIConnection = do+   req <- N.parseRequest "https://www.ncbi.nlm.nih.gov"+   manager <- N.newManager N.tlsManagerSettings+   response <- N.httpLbs req manager+   let sta = N.responseStatus response+   if statusIsSuccessful sta+     then return (Right "Network connection with NCBI server was successful")+     else return (Left ("Could not connect to NCBI server \"https://www.ncbi.nlm.nih.gov\". Response Code: " ++ show (statusCode sta) ++ " \n" ++ B.unpack (statusMessage sta)))++-- | Blast evalue is set stricter in inital alignment mode+setBlastExpectThreshold :: ModelConstruction -> Double+setBlastExpectThreshold modelConstruction+  | alignmentModeInfernal modelConstruction = 1 :: Double+  | otherwise = 0.1 :: Double++reformatFasta :: Fasta () () -> Fasta () ()+reformatFasta input = Fasta (_header input) updatedSequence+  where updatedSequence = BioSequence (B.pack (map reformatFastaSequence (B.unpack . _bioSequence . _fasta $ input)))++reformatFastaSequence :: Char -> Char+reformatFastaSequence c+  | c == '.' = '-'+  | c == '~' = '-'+  | c == '_' = '-'+  | c == 'u' = 'T'+  | c == 't' = 'T'+  | c == 'g' = 'G'+  | c == 'c' = 'C'+  | c == 'a' = 'A'+  | c == 'U' = 'T'+  | otherwise = c++setRestrictedTaxonomyLimits :: String -> (Maybe Int,Maybe Int)+setRestrictedTaxonomyLimits trestriction+  | trestriction == "bacteria" = (Just (2 :: Int), Nothing)+  | trestriction == "archea" = (Just (2157 :: Int), Nothing)+  | trestriction == "eukaryia" = (Just (2759 :: Int), Nothing)+  | otherwise = (Nothing, Nothing)++checkTaxonomyRestriction :: Maybe String -> Maybe String+checkTaxonomyRestriction taxonomyRestriction+  | isJust taxonomyRestriction = checkTaxonomyRestrictionString (fromJust taxonomyRestriction)+  | otherwise = Nothing++checkTaxonomyRestrictionString :: String -> Maybe String+checkTaxonomyRestrictionString restrictionString+  | restrictionString == "archea" = Just "archea"+  | restrictionString == "bacteria" = Just "bacteria"+  | restrictionString == "eukaryia" = Just "eukaryia"+  | otherwise = Nothing++extractAlignmentSequencesByIds :: String -> [B.ByteString] -> IO [Fasta () ()]+extractAlignmentSequencesByIds stockholmFilePath sequenceIds = do+  inputSeedAln <- TIO.readFile stockholmFilePath+  let alnEntries = extractAlignmentSequences inputSeedAln+  --let splitIds = map E.encodeUtf8 (TL.splitOn (TL.pack ",") (TL.pack sequenceIds))+  let filteredEntries = concatMap (filterSequencesById alnEntries) sequenceIds+  return filteredEntries++extractAlignmentSequences :: TL.Text -> [Fasta () ()]+extractAlignmentSequences  seedFamilyAln = rfamIDAndseedFamilySequences+  where seedFamilyAlnLines = TL.lines seedFamilyAln+        -- remove empty lines from splitting+        seedFamilyNonEmpty =  filter (\alnline -> TL.empty /= alnline) seedFamilyAlnLines+        -- remove annotation and spacer lines+        seedFamilyIdSeqLines =  filter (\alnline -> not ((TL.head alnline) == '#') && not ((TL.head alnline) == ' ') && not ((TL.head alnline) == '/')) seedFamilyNonEmpty+        -- put id and corresponding seq of each line into a list and remove whitspaces+        seedFamilyIdandSeqLines = map TL.words seedFamilyIdSeqLines+        -- linewise tuples with id and seq without alinment characters - .+        seedFamilyIdandSeqLineTuples = map (\alnline -> (head alnline,filterAlnChars (last alnline))) seedFamilyIdandSeqLines+        -- line tuples sorted by id+        seedFamilyIdandSeqTupleSorted = sortBy (\tuple1 tuple2 -> compare (fst tuple1) (fst tuple2)) seedFamilyIdandSeqLineTuples+        -- line tuples grouped by id+        seedFamilyIdandSeqTupleGroups = groupBy (\tuple1 tuple2 -> fst tuple1 == fst tuple2) seedFamilyIdandSeqTupleSorted+        seedFamilySequences = map mergeIdSeqTuplestoSequence seedFamilyIdandSeqTupleGroups+        rfamIDAndseedFamilySequences = seedFamilySequences++filterSequencesById :: [Fasta () ()] -> B.ByteString -> [Fasta () ()]+filterSequencesById alignmentSequences sequenceId = filter (sequenceHasId sequenceId) alignmentSequences++sequenceHasId :: B.ByteString -> Fasta () () -> Bool+sequenceHasId sequenceId currentSequence = sequenceId == fastaHeader currentSequence++filterAlnChars :: TL.Text -> TL.Text+filterAlnChars cs = TL.filter (\c -> not (c == '-') && not (c == '.')) cs++mergeIdSeqTuplestoSequence :: [(TL.Text,TL.Text)] -> Fasta () ()+mergeIdSeqTuplestoSequence tuplelist = currentSequence+  where seqId = TL.toStrict (fst (head tuplelist))+        seqData = TL.toStrict (TL.concat (map snd tuplelist))+        currentSequence = Fasta (SequenceIdentifier (E.encodeUtf8 seqId)) (BioSequence (E.encodeUtf8 seqData))++readFastaFile :: String -> IO [Fasta () ()]+readFastaFile fastaFilePath = do+  inputFastaFile <- L.readFile fastaFilePath+  let inputFastas = byteStringToMultiFasta inputFastaFile+  return inputFastas++blast :: String -> Int  -> Maybe Int -> Maybe Int -> Maybe Double -> Bool -> BlastHTTPQuery -> IO (Either String J.BlastJSON2)+blast _tempDirPath threads upperTaxIdLimit lowerTaxIdLimit expectThreshold _blastSoftmaskingToggle blastHTTPQuery = do+  --buildTaxonomyContext+  let upperTaxIdLimitPath = if isJust upperTaxIdLimit then _tempDirPath ++ "/upper.txids" else ""+  let lowerTaxIdLimitPath = if isJust lowerTaxIdLimit then _tempDirPath ++ "/lower.txids" else ""+  when (isJust upperTaxIdLimit) $ systemGetSpeciesTaxId (fromJust upperTaxIdLimit) upperTaxIdLimitPath+  when (isJust lowerTaxIdLimit) $ systemGetSpeciesTaxId (fromJust lowerTaxIdLimit) lowerTaxIdLimitPath+  let positiveSetTaxIdLimitPath = _tempDirPath ++ "/postitiveset.txids"+  if isJust lowerTaxIdLimit && isJust upperTaxIdLimit+    then do+      upperTaxIdsFile <- readFile upperTaxIdLimitPath+      let upperTaxIds = lines upperTaxIdsFile+      lowerTaxIdsFile <- readFile lowerTaxIdLimitPath+      let lowerTaxIds = lines lowerTaxIdsFile+      let positiveSetTaxIds = upperTaxIds \\ lowerTaxIds+      let positiveSetTaxIdsFile = unlines positiveSetTaxIds+      writeFile positiveSetTaxIdLimitPath positiveSetTaxIdsFile+    else return ()+  --sequenceSearch+  let fastaFilePath = _tempDirPath ++ "/blastQuery.fa"+  let blastResultFilePath = _tempDirPath ++ "/blastResult.json2"+  let selectedBlastDatabase = fromMaybe "" (Biobase.BLAST.HTTP.database blastHTTPQuery)+  writeFastaFile fastaFilePath (querySequences blastHTTPQuery)+  systemBlast threads selectedBlastDatabase upperTaxIdLimitPath lowerTaxIdLimitPath positiveSetTaxIdLimitPath expectThreshold _blastSoftmaskingToggle fastaFilePath blastResultFilePath+  blastCmdResult <- BBI.blastCmdJSON2FromFile blastResultFilePath+  --if isLeft blastResult then print (fromLeft blastResult) else print ""+  if isRight blastCmdResult+    then do+      let blastCmdOutput = J._blastcmdoutput2 (fromRight blastCmdResult)+      when ((length blastCmdOutput) > 1) $ print "Blast output list with multiple elements"+      if (not (null blastCmdOutput))+        then (return (Right (J.BlastJSON2 (head blastCmdOutput)):: Either String J.BlastJSON2))+        else (return (Left "Empty BlastOutput List" :: Either String J.BlastJSON2))+    else (return (Left (fromLeft blastCmdResult) :: Either String J.BlastJSON2))++-- | Run external blast command +systemBlast :: Int -> String -> String -> String -> String -> Maybe Double -> Bool -> String -> String -> IO ExitCode+systemBlast threads _blastDatabase upperTaxLimitPath lowerTaxLimitPath positiveSetTaxIdLimitPath _evalueThreshold _blastSoftmaskingToggle queryFilepath outputFilePath = do+  let cmd = ("blastn " ++ threadedOption ++ expectThresholdOption ++ taxonomyOption ++ " " ++ softmaskOption ++ dbOption ++ " -query " ++ queryFilepath  ++ " -outfmt 15  -out " ++ outputFilePath)+  putStrLn cmd+  system cmd+  where threadedOption = " -num_threads " ++ show threads+        expectThresholdOption = if isJust _evalueThreshold then " -evalue " ++ show (fromJust _evalueThreshold) else ""+        dbOption = if null _blastDatabase then "" else " -db " ++ _blastDatabase ++ " "+        softmaskOption = if _blastSoftmaskingToggle then " -soft_masking " else ""+        taxonomyOption = setBlastCallTaxonomyOptions upperTaxLimitPath lowerTaxLimitPath positiveSetTaxIdLimitPath++setBlastCallTaxonomyOptions :: String -> String -> String -> String+setBlastCallTaxonomyOptions upperTaxLimitPath lowerTaxLimitPath positiveSetTaxIdLimitPath+  | and [(not (null upperTaxLimitPath)),(not (null lowerTaxLimitPath))] = " -taxidlist " ++ positiveSetTaxIdLimitPath ++ " "+  | not (null upperTaxLimitPath) = " -taxidlist " ++ upperTaxLimitPath ++ " "+  | not (null lowerTaxLimitPath) = " -negative_taxidlist " ++ lowerTaxLimitPath ++ " "+  | otherwise = ""+             +-- | Retrieve taxids for blast +systemGetSpeciesTaxId :: Int -> String -> IO ()+systemGetSpeciesTaxId requestedTaxId outputFilePath = do+  system ("get_species_taxids.sh " ++ " -t " ++ show requestedTaxId  ++ " > " ++ outputFilePath)+  return ()+++
+ Biobase/RNAlien/RNAcentralHTTP.hs view
@@ -0,0 +1,134 @@+{-# LANGUAGE OverloadedStrings #-}++{-# LANGUAGE DeriveGeneric #-}++-- | Interface for the RNAcentral REST webservice.+--   +module Biobase.RNAlien.RNAcentralHTTP (rnaCentralHTTP,+                      buildSequenceViaMD5Query,+                      buildStringViaMD5Query,+                      getRNACentralEntries,+                      showRNAcentralAlienEvaluation,+                      RNAcentralEntryResponse(..),+                      RNAcentralEntry(..)+                      ) where++import Network.HTTP.Conduit+import qualified Data.ByteString.Lazy.Char8 as L8+--import qualified Data.ByteString.Char8 as BS8+import Network.Socket+import Control.Concurrent+import Data.Text+import Data.Aeson+import GHC.Generics+import qualified Data.Digest.Pure.MD5 as M+import Data.Either+import Biobase.Fasta.Strict+import Biobase.Types.BioSequence++--Datatypes+-- | Data structure for RNAcentral entry response+data RNAcentralEntryResponse = RNAcentralEntryResponse+  {+    count :: Int,+    next :: Maybe Text,+    previous :: Maybe Text,+    results :: [RNAcentralEntry]+  }+  deriving (Show, Eq, Generic)++instance ToJSON RNAcentralEntryResponse where+  toJSON = genericToJSON defaultOptions+  --toEncoding = genericToEncoding defaultOptions++instance FromJSON RNAcentralEntryResponse++data RNAcentralEntry = RNAcentralEntry+  {+    url :: Text,+    rnacentral_id :: Text,+    md5 :: Text,+    sequence :: Text,+    length :: Int,+    xrefs :: Text,+    publications :: Text+  }+  deriving (Show, Eq, Generic)++instance ToJSON RNAcentralEntry where+  toJSON = genericToJSON defaultOptions+  --toEncoding = genericToEncoding defaultOptions++instance FromJSON RNAcentralEntry++-- | Send query and parse return XML +startSession :: String -> IO (Either String RNAcentralEntryResponse)+startSession query' = do+  requestXml <- withSocketsDo+      $ sendQuery query'+  --putStr (L8.unpack requestXml)+  let eitherErrorResponse = eitherDecode requestXml :: Either String RNAcentralEntryResponse+  return eitherErrorResponse++-- | Send query and return response XML+sendQuery :: String -> IO L8.ByteString+sendQuery query' = do+   let address = "http://rnacentral.org/api/v1/rna/"+   let request = address ++ query'+   --putStrLn request+   simpleHttp request++-- | Function for querying the RNAcentral REST interface.+rnaCentralHTTP :: String -> IO (Either String RNAcentralEntryResponse)+rnaCentralHTTP query' =+  startSession query'++-- | Function for delayed queries to the RNAcentral REST interface. Enforces the maximum 20 requests per second policy.+delayedRNACentralHTTP :: String -> IO (Either String RNAcentralEntryResponse)+delayedRNACentralHTTP query' = do+  threadDelay 55000+  startSession query'++getRNACentralEntries :: [String] -> IO [Either String RNAcentralEntryResponse]+getRNACentralEntries queries = do+  mapM delayedRNACentralHTTP queries++-- | Build a query from a input sequence+--+-- TODO [chzs] consider using strict bytestring as long as possible.+--+-- TODO [chzs] consider giving useful typelevel names to the types in @Fasta@.+-- One may give a type-level name to the sequence identifier, and an identifier+-- (like @DNA@) to the biosequence type.++buildSequenceViaMD5Query :: Fasta () () -> String+buildSequenceViaMD5Query s = qString+  where querySequence = L8.fromStrict . _bioSequence $ _fasta s+        querySequenceUreplacedwithT = L8.map bsreplaceUT querySequence+        querySequenceU2Twolb = L8.filter ((/= '\n')) querySequenceUreplacedwithT+        md5Sequence = M.md5 querySequenceU2Twolb+        qString = "?md5=" ++ show md5Sequence++--Build a query from a input string+buildStringViaMD5Query :: String -> String+buildStringViaMD5Query s = qString+  where querySequenceUreplacedwithT = L8.map bsreplaceUT (L8.pack s)+        querySequenceU2Twolb = L8.filter ((/= '\n')) querySequenceUreplacedwithT+        md5Sequence = M.md5 querySequenceU2Twolb+        qString = "?md5=" ++ show md5Sequence++showRNAcentralAlienEvaluation :: [Either String RNAcentralEntryResponse] -> String+showRNAcentralAlienEvaluation responses = output+  where resultEntries = Prelude.concatMap results (rights responses)+        resulthead = "rnacentral_id\tmd5\tlength\n"+        resultentries = Prelude.concatMap showRNAcentralAlienEvaluationLine resultEntries+        output = if Prelude.null resultentries then "No matching sequences found in RNAcentral\n" else resulthead ++ resultentries++showRNAcentralAlienEvaluationLine :: RNAcentralEntry -> String+showRNAcentralAlienEvaluationLine entry = unpack (rnacentral_id entry) ++ "\t" ++ unpack (md5 entry) ++ "\t" ++ show (Biobase.RNAlien.RNAcentralHTTP.length entry) ++"\n"++bsreplaceUT :: Char -> Char+bsreplaceUT a+  | a == 'U' = 'T'+  | otherwise = a+
+ Biobase/RNAlien/Types.hs view
@@ -0,0 +1,145 @@+-- | This module contains data structures for RNAlien++module Biobase.RNAlien.Types where++import Biobase.Fasta.Strict+import Bio.Taxonomy+--import Biobase.Types.BioSequence+import qualified Data.ByteString.Char8 as B++-- | Static construction options+data StaticOptions = StaticOptions+  { tempDirPath :: String,+    sessionID :: String,+    nSCICutoff :: Double,+    userTaxId :: Maybe Int,+    singleHitperTaxToggle :: Bool,+    querySelectionMethod :: String,+    queryNumber :: Int,+    lengthFilterToggle :: Bool,+    coverageFilterToggle :: Bool,+    blastSoftmaskingToggle :: Bool,+    cpuThreads :: Int,+    blastDatabase :: Maybe String,+    taxRestriction :: Maybe String,+    verbositySwitch :: Bool,+    offline :: Bool+  } deriving (Show)++-- | Keeps track of model construction+data ModelConstruction = ModelConstruction+  { iterationNumber :: Int,+    inputFasta :: [Fasta () ()],+    taxRecords :: [TaxonomyRecord],+    --Taxonomy ID of the highest node in taxonomic subtree used in search+    upperTaxonomyLimit :: Maybe Int,+    taxonomicContext :: Maybe Taxon,+    evalueThreshold :: Double,+    alignmentModeInfernal :: Bool,+    selectedQueries :: [Fasta () ()],+    potentialMembers :: [SearchResult]+  }++instance Show ModelConstruction where+  show (ModelConstruction _iterationNumber _inputFasta _taxRecords _upperTaxonomyLimit _taxonomicContext _evalueThreshold _alignmentModeInfernal _selectedQueries _potentialMembers) = a ++ b ++ c ++ d ++ e ++ g ++ h ++ i+    where a = "Modelconstruction iteration: " ++ show _iterationNumber ++ "\n"+          -- b = "Input fasta:\n" ++ concatMap (prettyPrintFasta 80) _inputFasta  -- L.unpack (fastaHeader _inputFasta)  ++ "\n" ++ L.unpack (fastaSequence _inputFasta) ++ "\n"+          b = "Input fasta:\n" ++ concatMap (convertString . fastaToByteString 80) _inputFasta+          c = show _taxRecords+          d = "Upper taxonomy limit: " ++ maybe "not set" show _upperTaxonomyLimit ++ "\n"+          e = "Taxonomic Context: " ++  maybe "not set" show _taxonomicContext ++ "\n"+          g = "Evalue cutoff: " ++ show _evalueThreshold ++ "\n"+          h = "Selected queries: \n" ++ concatMap show _selectedQueries+          i = "Potential Members: \n" ++ concatMap show _potentialMembers++data TaxonomyRecord = TaxonomyRecord+  { recordTaxonomyId :: Int,+    sequenceRecords :: [SequenceRecord]+  }++instance Show TaxonomyRecord where+  show (TaxonomyRecord _recordTaxonomyId _sequenceRecords) = a ++ b+    where a = "TaxonomyRecord TaxonomyId: " ++ show _recordTaxonomyId ++ "\n"+          b = show _sequenceRecords++data SequenceRecord = SequenceRecord+  { --Sequence consisting of SeqLabel, and SeqData+    nucleotideSequence :: Fasta () (),+    -- 0 is unaligned, number is the iteration the sequence has been included into the alignment+    aligned  :: Int,+    recordDescription :: B.ByteString+  }++instance Show SequenceRecord where+  show (SequenceRecord _nucleotideSequence _aligned _recordDescription) = a ++ b ++ c+    where a = "Record Description: " ++ B.unpack _recordDescription ++ "\n"+          b = "Aligned in iteration: " ++ show _aligned ++ "\n"+          c = "Sequence:" ++ show _nucleotideSequence ++ "\n"+-- |+data CMsearch = CMsearch+  { queryCMfile :: String,+    targetSequenceDatabase :: String,+    numberOfWorkerThreads :: String,+    cmsearchHits :: [CMsearchHit]+--    hitAlignments :: [CMsearchHitAlignment]+--    internalCMPipelineStatisticsSummary+  } deriving (Show, Eq, Read)++-- |+data CMsearchHit = CMsearchHit+  { hitRank :: Int,+    hitSignificance :: Char,+    hitEvalue :: Double,+    hitScore :: Double,+    hitBias :: Double,+    hitSequenceHeader :: B.ByteString,+    hitStart :: Int,+    hitEnd :: Int,+    hitStrand :: Char,+    hitModel :: B.ByteString,+    hitTruncation :: B.ByteString,+    hitGCContent :: Double,+    hitDescription :: B.ByteString+  } deriving (Show, Eq, Read)++data SearchResult = SearchResult+  { candidates :: [(Fasta () (),Int,B.ByteString)],+    blastDatabaseSize :: Maybe Double+  }++instance Show SearchResult where+  show (SearchResult _candidates _blastDatabaseSize) = a ++ b+    where a = "SearchResults :\n " ++ concatMap show _candidates ++ "\n"+          b = "BlastDb Size: " ++ show _blastDatabaseSize ++ "\n"++-- |+data CMstat = CMstat+  { statIndex :: Int,+    statName :: String,+    statAccession :: String,+    statSequenceNumber :: Int,+    statEffectiveSequences :: Double,+    statConsensusLength :: Int,+    -- W The expected maximum length of a hit to the model.+    statW :: Int,+    statBasepairs :: Int,+    statBifurcations :: Int,+    statModel :: String,+    relativeEntropyCM :: Double,+    relativeEntropyHMM :: Double+  } deriving (Eq, Read)++instance Show CMstat where+  show (CMstat _statIndex _statName _statAccession _statSequenceNumber _statEffectiveSequences _statConsensusLength _statW _statBasepairs _statBifurcations _statModel _relativeEntropyCM _relativeEntropyHMM) = a ++ b ++ c ++ d ++ e ++ f ++ g ++ h ++ i ++ j ++ k ++ l+    where a = "CMstat - covariance model statistics:\nIndex: " ++ show _statIndex ++ "\n"+          b = "Name: " ++ show _statName ++ "\n"+          c = "Accession: " ++ show _statAccession ++ "\n"+          d = "Sequence Number: " ++ show _statSequenceNumber ++ "\n"+          e = "Effective Sequences: " ++ show _statEffectiveSequences ++ "\n"+          f = "Consensus length: " ++ show _statConsensusLength ++ "\n"+          g = "Expected maximum hit-length: " ++ show _statW ++ "\n"+          h = "Basepairs: " ++ show _statBasepairs ++ "\n"+          i = "Bifurcations: " ++ show _statBifurcations ++ "\n"+          j = "Modeltype: " ++ show _statModel ++ "\n"+          k = "Relative Entropy CM: " ++ show _relativeEntropyCM ++ "\n"+          l = "Relative Entropy HMM: " ++ show _relativeEntropyHMM ++ "\n"
+ Biobase/RNAlienStatistics.hs view
@@ -0,0 +1,331 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE DeriveDataTypeable #-}++-- | Statistics for RNAlien Results+-- dist/build/RNAlienStatistics/RNAlienStatistics -s bitscore -i /scratch/egg/temp/cm13676/1/model.cm -r /home/mescalin/egg/current/Data/AlienTest/cms/BsrG.cm -g /scratch/egg/temp/AlienSearch/genomes/ -o /scratch/egg/temp/AlienStatistics+module Main where++import System.Console.CmdArgs+import Data.Either.Unwrap+import System.Process+import qualified Data.ByteString.Char8 as B+import Biobase.RNAlien.Library+import System.Directory+import Biobase.Fasta.Strict+import Data.List+import qualified System.FilePath as FP+import qualified Data.List.Split as DS+import Text.Printf+import Bio.RNAzParser+import qualified Bio.RNAcodeParser as RC+import Biobase.Types.BioSequence++data Options = Options+  { alienCovarianceModelPath  :: String,+    alienrnazPath :: String,+    alienrnacodePath :: String,+    aliencmstatPath :: String,+    rfamCovarianceModelPath :: String,+    rfamFastaFilePath :: String,+    alienFastaFilePath :: String,+    rfamModelName :: String,+    rfamModelId :: String,+    rfamThreshold :: Double,+    alienThreshold :: Double,+    databaseSize :: Maybe Double,+    outputDirectoryPath :: String,+    benchmarkIndex :: Int,+    thresholdSelection :: String,+    linkScores :: Bool,+    threads :: Int+  } deriving (Show,Data,Typeable)++options :: Options+options = Options+  { alienCovarianceModelPath = def &= name "i" &= help "Path to alienCovarianceModelPath",+    alienrnazPath = def &= name "z" &= help "Path to alienRNAzResult",+    alienrnacodePath = def &= name "w" &= help "Path to alienRNAcodeResult",+    aliencmstatPath = def &= name "m" &= help "Path to aliencmstatResult",+    rfamCovarianceModelPath = def &= name "r" &= help "Path to rfamCovarianceModelPath",+    rfamFastaFilePath = def &= name "g" &= help "Path to rfamFastaFile",+    rfamModelName = def &= name "n" &= help "Rfam model name",+    rfamModelId = def &= name "d" &= help "Rfam model id",+    alienFastaFilePath = def &= name "a" &= help "Path to alienFastaFile",+    outputDirectoryPath = def &= name "o" &= help "Path to output directory",+    alienThreshold = 20 &= name "t" &= help "Bitscore threshold for RNAlien model hits on Rfam fasta, default 20",+    rfamThreshold = 20 &= name "x" &= help "Bitscore threshold for Rfam model hits on Alien fasta, default 20",+    databaseSize = Nothing  &= name "k" &= help "Cmsearch database size in mega bases. default not set",+    benchmarkIndex = 1 &= name "b" &= help "Index used to identify sRNA tagged RNA families",+    thresholdSelection = "bitscore" &= name "s" &= help "Selection method, (bitscore, evalue), default bitscore",+    linkScores = False &= name "l" &= help "Triggers computation of linkscores via CMCompare",+    threads = 1 &= name "c" &= help "Number of available cpu slots/cores, default 1"+  } &= summary "RNAlienStatistics" &= help "Florian Eggenhofer - >2013" &= verbosity++--cmSearchFasta threads rfamCovarianceModelPath outputDirectoryPath "Rfam" False genomesDirectoryPath+cmSearchFasta :: Int -> String -> Double -> Maybe Double -> Int -> String -> String -> String -> String -> IO [CMsearchHit]+cmSearchFasta benchmarkIndex thresholdSelection thresholdScore databaseSize cpuThreads covarianceModelPath outputDirectory modelType fastapath = do+  createDirectoryIfMissing False (outputDirectory ++ "/" ++ modelType)+  _ <- systemCMsearch cpuThreads (maybe "" (\dbs -> " -Z " ++ show dbs ++ " ") databaseSize)  covarianceModelPath fastapath (outputDirectory ++ "/" ++ modelType ++ "/" ++ show benchmarkIndex ++ ".cmsearch")+  --_ <- systemCMsearch cpuThreads " " covarianceModelPath fastapath (outputDirectory ++ "/" ++ modelType ++ "/" ++ (show benchmarkIndex) ++ ".cmsearch")+  result <- readCMSearch (outputDirectory ++ "/" ++ modelType ++ "/" ++ show benchmarkIndex ++ ".cmsearch")+  if isLeft result+     then do+       print (fromLeft result)+       return []+     else do+       let rightResults = fromRight result+       let significantHits = filterCMsearchHits thresholdSelection thresholdScore rightResults+       let uniquesignificantHits = nubBy cmSearchSameHit significantHits+       return uniquesignificantHits++--cmSearchFasta threads rfamCovarianceModelPath outputDirectoryPath "Rfam" False genomesDirectoryPath+cmSearchesFasta :: Int -> String -> Double -> Maybe Double -> Int -> String -> String -> String -> String -> IO [CMsearchHit]+cmSearchesFasta benchmarkIndex thresholdSelection thresholdScore databaseSize cpuThreads covarianceModelPath outputDirectory modelType fastapath = do+  createDirectoryIfMissing False (outputDirectory ++ "/" ++ modelType)+  _ <- systemCMsearch cpuThreads (maybe "" (\dbs -> " -Z " ++ show dbs ++ " ") databaseSize) covarianceModelPath fastapath (outputDirectory ++ "/" ++ modelType ++ "/" ++ show benchmarkIndex ++ ".cmsearch")+  --_ <- systemCMsearch cpuThreads " " covarianceModelPath fastapath (outputDirectory ++ "/" ++ modelType ++ "/" ++ (show benchmarkIndex) ++ ".cmsearch")+  result <- readCMSearches (outputDirectory ++ "/" ++ modelType ++ "/" ++ show benchmarkIndex ++ ".cmsearch")+  if isLeft result+     then do+       print (fromLeft result)+       return []+     else do+       let rightResults = fromRight result+       let significantHits = filterCMsearchHits thresholdSelection thresholdScore rightResults+       --putStrLn ("significant Hits " ++ show (length significantHits))+       let uniquesignificantHits = nubBy cmSearchSameHit significantHits+       --putStrLn ("unique significant Hits " ++ show (length uniquesignificantHits))+       --let organismUniquesignificantHits = nubBy cmSearchSameOrganism significantHits+       return uniquesignificantHits++filterCMsearchHits :: String -> Double -> CMsearch -> [CMsearchHit]+filterCMsearchHits thresholdSelection thresholdScore cmSearchResult+  | thresholdSelection == "bitscore" = bitscorefiltered+  | otherwise =  evaluefiltered+  where bitscorefiltered = filter (\hit -> hitScore hit >= thresholdScore) (cmsearchHits cmSearchResult)+        evaluefiltered = filter (\hit -> hitEvalue hit <= thresholdScore) (cmsearchHits cmSearchResult)++partitionCMsearchHits :: String -> Double -> CMsearch -> ([CMsearchHit],[CMsearchHit])+partitionCMsearchHits thresholdSelection thresholdScore cmSearchResult+  | thresholdSelection == "bitscore" = (bitscoreselected,bitscorerejected)+  | otherwise =  (evalueselected,evaluerejected)+  where (bitscoreselected,bitscorerejected) = partition (\hit -> hitScore hit >= thresholdScore) (cmsearchHits cmSearchResult)+        (evalueselected,evaluerejected) = partition (\hit -> hitEvalue hit <= thresholdScore) (cmsearchHits cmSearchResult)++trimCMsearchFastaFile :: String -> String -> String -> CMsearch -> String -> IO ()+trimCMsearchFastaFile genomesDirectory outputFolder modelType cmsearch fastafile  = do+  let fastaInputPath = genomesDirectory ++ "/" ++ fastafile+  let fastaOutputPath = outputFolder ++ "/" ++ modelType ++ "/" ++ fastafile+  fastaSequences <- readFastaFile fastaInputPath+  let trimmedSequence = trimCMsearchSequence cmsearch (head fastaSequences)+  writeFastaFile fastaOutputPath [trimmedSequence]++trimCMsearchSequence :: CMsearch -> Fasta () () -> Fasta () ()+trimCMsearchSequence cmSearchResult inputSequence = subSequence+  where hitScoreEntry = head (cmsearchHits cmSearchResult)+        sequenceString = show (_fasta inputSequence)+        sequenceSubstring = cmSearchsubString (hitStart hitScoreEntry) (hitEnd hitScoreEntry) sequenceString+        newSequenceHeader = SequenceIdentifier (B.pack (show (_header inputSequence) ++ "cmS_" ++ show (hitStart hitScoreEntry) ++ "_" ++ show (hitEnd hitScoreEntry) ++ "_" ++ show (hitStrand hitScoreEntry)))+        subSequence = Fasta newSequenceHeader (BioSequence (B.pack sequenceSubstring))++--With paralogs allowed+cmSearchSameHit :: CMsearchHit -> CMsearchHit -> Bool+cmSearchSameHit hitscore1 hitscore2+  | unpackedSeqHeader1 == unpackedSeqHeader2 = True+  | otherwise = False+  where unpackedSeqHeader1 = B.unpack (hitSequenceHeader hitscore1)+        unpackedSeqHeader2 = B.unpack (hitSequenceHeader hitscore2)++cmSearchSameOrganism :: CMsearchHit -> CMsearchHit -> Bool+cmSearchSameOrganism hitscore1 hitscore2+  | hitOrganism1 == hitOrganism2 = True+  | otherwise = False+  where unpackedSeqHeader1 = B.unpack (hitSequenceHeader hitscore1)+        unpackedSeqHeader2 = B.unpack (hitSequenceHeader hitscore2)+        separationcharacter1 = selectSeparationChar unpackedSeqHeader1+        separationcharacter2 = selectSeparationChar unpackedSeqHeader2+        hitOrganism1 = head (DS.splitOn separationcharacter1 unpackedSeqHeader1)+        hitOrganism2 = head (DS.splitOn separationcharacter2 unpackedSeqHeader2)++selectSeparationChar :: String -> String+selectSeparationChar inputString+  | any ((== ':')) inputString = ":"+  | otherwise = "/"++main :: IO ()+main = do+  Options{..} <- cmdArgs options+  rfamModelExists <- doesFileExist rfamCovarianceModelPath+  verbose <- getVerbosity+  rnazString <- rnazOutput verbose alienrnazPath+  rnacodeString <- rnaCodeOutput verbose alienrnacodePath+  cmStatString <- cmStatOutput verbose aliencmstatPath+  if rfamModelExists+    then do+      --compute linkscore+      linkscore <- if linkScores+        then compareCM rfamCovarianceModelPath alienCovarianceModelPath outputDirectoryPath+        else return (Left "-")+      rfamMaxLinkScore <- if linkScores then compareCM rfamCovarianceModelPath rfamCovarianceModelPath outputDirectoryPath else return (Left "-")+      alienMaxLinkscore <- if linkScores then compareCM alienCovarianceModelPath alienCovarianceModelPath outputDirectoryPath else return (Left "-")+      _ <- system ("cat " ++ rfamFastaFilePath ++ " | grep '>' | wc -l >" ++ outputDirectoryPath ++ FP.takeFileName rfamFastaFilePath ++ ".entries")+      _ <- system ("cat " ++ alienFastaFilePath ++ " | grep '>' | wc -l >" ++ outputDirectoryPath ++ FP.takeFileName alienFastaFilePath ++ ".entries")+      rfamFastaEntries <- readFile (outputDirectoryPath ++ FP.takeFileName rfamFastaFilePath ++ ".entries")+      alienFastaEntries <- readFile (outputDirectoryPath ++ FP.takeFileName alienFastaFilePath ++ ".entries")+      let rfamFastaEntriesNumber = read rfamFastaEntries :: Int+      let alienFastaEntriesNumber = read alienFastaEntries :: Int+      rfamonAlienResults <- cmSearchesFasta benchmarkIndex thresholdSelection rfamThreshold databaseSize threads rfamCovarianceModelPath outputDirectoryPath "rfamOnAlien" alienFastaFilePath+      alienonRfamResults <- cmSearchFasta benchmarkIndex thresholdSelection alienThreshold databaseSize threads alienCovarianceModelPath outputDirectoryPath "alienOnRfam" rfamFastaFilePath+      let rfamonAlienResultsNumber = length rfamonAlienResults+      let alienonRfamResultsNumber = length alienonRfamResults+      let rfamonAlienRecovery = (fromIntegral rfamonAlienResultsNumber :: Double) / (fromIntegral alienFastaEntriesNumber :: Double)+      let alienonRfamRecovery = (fromIntegral alienonRfamResultsNumber :: Double) / (fromIntegral rfamFastaEntriesNumber :: Double)+      if verbose == Loud+        then do+          putStrLn ("BenchmarkIndex: " ++ show benchmarkIndex)+          putStrLn ("RfamModelName: " ++ rfamModelName)+          putStrLn ("RfamModelId: " ++ rfamModelId)+          putStrLn ("Linkscore: " ++ either id show linkscore)+          putStrLn ("rfamMaxLinkScore: " ++ either id show rfamMaxLinkScore)+          putStrLn ("alienMaxLinkscore: " ++ either id show alienMaxLinkscore)+          putStrLn ("rfamGatheringThreshold: " ++ show rfamThreshold)+          putStrLn ("alienGatheringThreshold: " ++ show alienThreshold)+          putStrLn ("rfamFastaEntriesNumber: " ++ show rfamFastaEntriesNumber)+          putStrLn ("alienFastaEntriesNumber: " ++ show alienFastaEntriesNumber)+          putStrLn ("rfamonAlienResultsNumber: " ++ show rfamonAlienResultsNumber)+          putStrLn ("alienonRfamResultsNumber: " ++ show alienonRfamResultsNumber)+          putStrLn ("RfamonAlienRecovery: " ++ show rfamonAlienRecovery)+          putStrLn ("AlienonRfamRecovery: " ++ show alienonRfamRecovery)+          print rnazString+          print rnacodeString+          print cmStatString+        else+          putStrLn (show benchmarkIndex ++ "\t" ++ rfamModelName ++ "\t" ++ rfamModelId ++ "\t" ++  (either id show linkscore) ++ "\t" ++  (either id show rfamMaxLinkScore) ++ "\t" ++ (either id show alienMaxLinkscore) ++ "\t" ++ show rfamThreshold ++ "\t" ++ show alienThreshold ++ "\t" ++ show rfamFastaEntriesNumber ++ "\t" ++ show alienFastaEntriesNumber ++ "\t" ++ show rfamonAlienResultsNumber ++ "\t" ++ show alienonRfamResultsNumber ++ "\t" ++ printf "%.2f" rfamonAlienRecovery  ++ "\t" ++ printf "%.2f" alienonRfamRecovery ++ "\t" ++ rnazString ++ "\t" ++ rnacodeString ++ "\t" ++ cmStatString)+    else do+      --compute linkscore+      alienMaxLinkscore <- if linkScores then compareCM alienCovarianceModelPath alienCovarianceModelPath outputDirectoryPath else return ( Left "-")+      _ <- system ("cat " ++ alienFastaFilePath ++ " | grep '>' | wc -l >" ++ outputDirectoryPath ++ FP.takeFileName alienFastaFilePath ++ ".entries")+      alienFastaEntries <- readFile (outputDirectoryPath ++ FP.takeFileName alienFastaFilePath ++ ".entries")+      let alienFastaEntriesNumber = read alienFastaEntries :: Int+      if verbose == Loud+        then do+          putStrLn "BenchmarkIndex:"+          putStrLn "RfamModelName: -"+          putStrLn "RfamModelId: -"+          putStrLn "Linkscore: -"+          putStrLn "rfamMaxLinkScore: -"+          putStrLn ("alienMaxLinkscore: " ++  either id show alienMaxLinkscore)+          putStrLn "rfamGatheringThreshold: -"+          putStrLn "alienGatheringThreshold: -"+          putStrLn "rfamFastaEntriesNumber: -"+          putStrLn ("alienFastaEntriesNumber: " ++ show alienFastaEntriesNumber)+          putStrLn "rfamonAlienResultsNumber: -"+          putStrLn "alienonRfamResultsNumber: -"+          putStrLn "RfamonAlienRecovery: -"+          putStrLn "AlienonRfamRecovery: -"+          print rnazString+          print cmStatString+        else+          putStrLn (show benchmarkIndex ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ (either id show alienMaxLinkscore) ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ show alienFastaEntriesNumber ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-"  ++ "\t" ++ "-" ++ "\t" ++ rnazString  ++ "\t" ++ rnacodeString ++ "\t" ++ cmStatString)++rnazOutput :: Verbosity -> String -> IO String+rnazOutput verbose rnazPath = do+  rnazPresent <- doesFileExist rnazPath+  if rnazPresent+    then do+      inputRNAz <- readRNAz rnazPath+      if isRight inputRNAz+        then do+          let rnaZ = fromRight inputRNAz+          if verbose == Loud+            then do+              let output = "Mean pairwise identity: " ++ show (meanPairwiseIdentity rnaZ) ++ "\n  Shannon entropy: " ++ show (shannonEntropy rnaZ) ++  "\n  GC content: " ++ show (gcContent rnaZ) ++ "\n  Mean single sequence minimum free energy: " ++ show (meanSingleSequenceMinimumFreeEnergy rnaZ) ++ "\n  Consensus minimum free energy: " ++ show (consensusMinimumFreeEnergy rnaZ) ++ "\n  Energy contribution: " ++ show (energyContribution rnaZ) ++ "\n  Covariance contribution: " ++ show (covarianceContribution rnaZ) ++ "\n  Combinations pair: " ++ show (combinationsPair rnaZ) ++ "\n  Mean z-score: " ++ show (meanZScore rnaZ) ++ "\n  Structure conservation index: " ++ show (structureConservationIndex rnaZ) ++ "\n  Background model: " ++ backgroundModel rnaZ ++ "\n  Decision model: " ++ decisionModel rnaZ ++ "\n  SVM decision value: " ++ show (svmDecisionValue rnaZ) ++ "\n  SVM class propability: " ++ show (svmRNAClassProbability rnaZ) ++ "\n  Prediction: " ++ prediction rnaZ+              return output+            else do+              let output = show (meanPairwiseIdentity rnaZ) ++ "\t" ++ show (shannonEntropy rnaZ) ++  "\t" ++ show (gcContent rnaZ) ++ "\t" ++ show (meanSingleSequenceMinimumFreeEnergy rnaZ) ++ "\t" ++ show (consensusMinimumFreeEnergy rnaZ) ++ "\t" ++ show (energyContribution rnaZ) ++ "\t" ++ show (covarianceContribution rnaZ) ++ "\t" ++ show (combinationsPair rnaZ) ++ "\t" ++ show (meanZScore rnaZ) ++ "\t" ++ show (structureConservationIndex rnaZ) ++ "\t" ++ show (svmDecisionValue rnaZ) ++ "\t" ++ show (svmRNAClassProbability rnaZ) ++ "\t" ++ prediction rnaZ+              return output+         else+           if (verbose == Loud)+            then do+              let output = "Mean pairwise identity: " ++ " - \n  Shannon entropy: " ++ " - \n  GC content: " ++ " - \n  Mean single sequence minimum free energy: " ++ " - \n  Consensus minimum free energy: " ++ " - \n  Energy contribution: " ++ " - \n  Covariance contribution: " ++ " - \n  Combinations pair: " ++ " - \n  Mean z-score: " ++ " - \n  Structure conservation index: " ++ " - \n  Background model: " ++ " - \n  Decision model: " ++ " - \n  SVM decision value: " ++ " - \n  SVM class propability: " ++ " - \n  Prediction: " ++ " - \n"+              return output+            else do+              let output = "-" ++ "\t" ++ "-" ++  "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-"+              return output+    else+       if (verbose == Loud)+         then do+           let output = "Mean pairwise identity: " ++ " - \n  Shannon entropy: " ++ " - \n  GC content: " ++ " - \n  Mean single sequence minimum free energy: " ++ " - \n  Consensus minimum free energy: " ++ " - \n  Energy contribution: " ++ " - \n  Covariance contribution: " ++ " - \n  Combinations pair: " ++ " - \n  Mean z-score: " ++ " - \n  Structure conservation index: " ++ " - \n  Background model: " ++ " - \n  Decision model: " ++ " - \n  SVM decision value: " ++ " - \n  SVM class propability: " ++ " - \n  Prediction: " ++ " - \n"+           return output+         else do+           let output = "-" ++ "\t" ++ "-" ++  "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-"+           return output++cmStatOutput :: Verbosity -> String -> IO String+cmStatOutput verbose cmstatPath = do+  cmstatPresent <- doesFileExist cmstatPath+  if cmstatPresent+    then do+      inputCMstat <- readCMstat cmstatPath+      if isRight inputCMstat+        then do+          let cmStat = fromRight inputCMstat+          if verbose == Loud+            then do+              let output = "statSequenceNumber: " ++ show (statSequenceNumber cmStat) ++ "\nstatEffectiveSequences: " ++ show (statEffectiveSequences cmStat) ++ "\nstatConsensusLength: " ++ show (statConsensusLength cmStat) ++ "\nstatW: " ++ show (statW cmStat) ++ "\nstatBasepairs: " ++ show (statBasepairs cmStat) ++ "\nstatBifurcations: " ++ show (statBifurcations cmStat) ++ "\nstatModel: " ++ statModel cmStat ++ "\nrelativeEntropyCM: " ++ show (relativeEntropyCM cmStat) ++ "\nrelativeEntropyHMM: " ++ show (relativeEntropyHMM cmStat)+              return output+            else do+              let output = show (statSequenceNumber cmStat) ++ "\t" ++ show (statEffectiveSequences cmStat) ++ "\t" ++ show (statConsensusLength cmStat) ++ "\t" ++ show (statW cmStat) ++ "\t" ++ show (statBasepairs cmStat) ++ "\t" ++ show (statBifurcations cmStat) ++ "\t" ++ statModel cmStat ++ "\t" ++ show (relativeEntropyCM cmStat) ++ "\t" ++ show (relativeEntropyHMM cmStat)+              return output+         else+           if (verbose == Loud)+            then do+              let output = "statSequenceNumber: -" ++ "\nstatEffectiveSequences: -" ++ "\nstatConsensusLength: -" ++ "\nstatW: -" ++ "\nstatBasepairs: -" ++ "\nstatBifurcations: -" ++ "\nstatModel: -" ++ "\nrelativeEntropyCM: -" ++ "\nrelativeEntropyHMM: -"+              return output+            else do+              let output = "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-"+              return output+    else+       if (verbose == Loud)+         then do+           let output = "statSequenceNumber: -" ++ "\nstatEffectiveSequences: -" ++ "\nstatConsensusLength: -" ++ "\nstatW: -" ++ "\nstatBasepairs: -" ++ "\nstatBifurcations: -" ++ "\nstatModel: -" ++ "\nrelativeEntropyCM: -" ++ "\nrelativeEntropyHMM: -"+           return output+         else do+           let output = "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-"+           return output++rnaCodeOutput :: Verbosity -> String -> IO String+rnaCodeOutput verbose rnaCodePath = do+  rnacodePresent <- doesFileExist rnaCodePath+  if rnacodePresent+    then do+      inputRNACode <- RC.readRNAcodeTabular rnaCodePath+      if isRight inputRNACode+        then do+          let rnaCode = fromRight inputRNACode+          let lowestPvalue = minimum (map RC.pvalue (RC.rnacodeHits rnaCode))+          let rnaCodeClassification = if lowestPvalue < 0.05 then "PROTEIN" else "OTHER"+          if verbose == Loud+            then do+              let output = "RNAcode lowest p-value: " ++ show lowestPvalue ++ "\nrnaCodeClassification: " ++ rnaCodeClassification+              return output+            else do+              let output = show lowestPvalue ++ "\t" ++ rnaCodeClassification+              return output+         else+           if (verbose == Loud)+            then do+              let output = "RNAcode lowest p-value: " ++ "-" ++ "\nrnaCodeClassification: " ++ "-"+              return output+            else do+              let output = "-\t" ++ "-"+              --let output = show (fromLeft inputRNACode)+              return output+    else+       if (verbose == Loud)+         then do+           let output =  "RNAcode lowest p-value: " ++ "-" ++ "\nrnaCodeClassification: " ++ "-"+           return output+         else do+           let output = "-\t" ++ "-"+           return output
+ Biobase/cmsearchToBED.hs view
@@ -0,0 +1,178 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE DeriveDataTypeable #-}++-- | Convert cmsearch output to Browser Extensible Data (BED) format+--   Testcommand: cmsearchToBED -i /path/to/test.clustal+module Main where+import Prelude+import System.Console.CmdArgs+import Biobase.RNAlien.Library+import Data.Either.Unwrap+import qualified Data.ByteString.Char8 as B+import qualified Data.Text as T+import Data.List++data Bed = Bed+  { browserPostition :: T.Text,+    browserSettings :: T.Text,+    bedName :: T.Text,+    bedDescription :: T.Text,+    bedVisibility :: Int,+    bedItemRgb :: Bool,+    bedEntries :: [BedEntry]+  } deriving (Eq, Read)++instance Show Bed where+  show (Bed _browserPostition _browserSettings _bedName _bedDescription _bedVisibility _bedItemRgb _bedEntries) = a ++ b ++ c ++ d ++ e ++ f ++ g+    where a = "browser position " ++ T.unpack _browserPostition ++ "\n"+          b = T.unpack _browserSettings ++ "\n"+          c = "track name=\"" ++ T.unpack _bedName  ++ "\" "+          d = "description=\"" ++ T.unpack _bedDescription ++ "\" "+          e = "visibility=" ++  show _bedVisibility ++ " "+          f = "itemRgb=\"" ++ itemRbg ++ "\"\n"+          itemRbg = if _bedItemRgb then "On" else "Off"+          g = concatMap show _bedEntries+++data BedEntry = BedEntry+  { chrom :: T.Text,+    chromStart :: Int,+    chromEnd  :: Int,+    chromName :: Maybe T.Text,+    score :: Maybe Int,+    strand :: Maybe Char,+    thickStart :: Maybe Int,+    thickEnd :: Maybe Int,+    color :: Maybe T.Text,+    blockCount :: Maybe Int,+    blockSizes :: Maybe [Int],+    blockStarts :: Maybe [Int]+  } deriving (Eq, Read)++instance Show BedEntry where+  show (BedEntry _chrom _chromStart _chromEnd _chromName _score _strand _thickStart _thickEnd _color _blockCount _blockSizes _blockStarts) = a ++ b ++ c ++ d ++ e ++ f ++ g ++ h ++ i ++ j ++ k ++ l+    where a = T.unpack _chrom ++ "\t"+          b = show _chromStart ++ "\t"+          c = show _chromEnd ++ "\t"+          d = maybe "" T.unpack _chromName ++ "\t"+          e = maybe "" show _score ++ "\t"+          f = maybe "" ((: []))  _strand ++ "\t"+          g = maybe "" show _thickStart ++ "\t"+          h = maybe "" show _thickEnd ++ "\t"+          i = maybe "" T.unpack _color ++ "\t"+          j = maybe "" show _blockCount ++ "\t"+          k = maybe "" (intercalate "," . map show) _blockSizes ++ "\t"+          l = maybe "" (intercalate "," . map show) _blockStarts ++ "\n"++data Options = Options+  { cmsearchPath :: String,+    inputBrowserSettings :: String,+    inputBedVisibility :: Int,+    inputTrackName :: String,+    inputTrackDescription :: String,+    inputItemRgb :: Bool,+    inputTrackColor :: String,+    sortBed :: Bool,+    withHeader :: Bool+  } deriving (Show,Data,Typeable)++options :: Options+options = Options+  { cmsearchPath = def &= name "i" &= help "Path to input cmsearch file",+    inputBrowserSettings = "browser hide all" &= name "b" &= help "Browser settings. Default: browser hide all",+    inputBedVisibility = (2 :: Int) &= name "y" &= help "Visibility setting of track. Default: 2",+    inputTrackName = "PredictedRNA" &= name "n" &= help "Name of the track Default: PredictedRNA",+    inputTrackDescription = "RNA loci predicted by cmsearch" &= name "d" &= help "Description of the track. Default: RNA loci predicted by cmsearch",+    inputItemRgb = True &= name "r" &= help "RGB Color of the track. Default: True",+    inputTrackColor = "255,0,0" &= name "c" &= help "RGB Color of the track. Default: 255,0,0",+    sortBed = True &= name "s" &= help "Sort entries of Bed file by start end end cooridinates. Default: True",+    withHeader = True &= name "w" &= help "Output contains bed header. Default: True"+  } &= summary "cmsearchToBED - Converts cmsearch file hits to BED file entries" &= help "Florian Eggenhofer 2016" &= verbosity++main :: IO ()+main = do+  Options{..} <- cmdArgs options+  parsedCmsearch <- readCMSearch cmsearchPath+  if isRight parsedCmsearch+     then do+       let outputBED = convertcmSearchToBED (fromRight parsedCmsearch) inputBrowserSettings inputTrackName inputTrackDescription inputTrackColor inputBedVisibility inputItemRgb sortBed+       if isRight outputBED+         then+           if withHeader+             then print (fromRight outputBED)+             else do+               let output = concatMap show (bedEntries (fromRight outputBED))+               putStr output+         else putStr (fromLeft outputBED)+     else putStr ("A problem occured converting from cmsearch to BED format:\n " ++ show (fromLeft parsedCmsearch))++--convertcmSearchToBED :: CMsearch -> String -> String -> Either String String+--convertcmSearchToBED inputcmsearch trackName trackColor+--  | null cmHits = Left "cmsearch file contains no hits" +--  | otherwise = Right (bedHeader ++ bedEntries)+--  where cmHits = cmsearchHits inputcmsearch+--        bedHeader = "browser position " ++ browserPosition ++ "\nbrowser hide all\ntrack name=\"cmsearch hits\" description=\"cmsearch hits\" visibility=2 itemRgb=\"On\"\n"+--        bedEntries = concatMap (cmsearchHitToBEDentry trackName trackColor) cmHits+--        browserPosition = L.unpack (hitSequenceHeader firstHit) ++ ":" ++ entryStart firstHit ++ "-" ++ entryEnd firstHit+--        firstHit = (head cmHits)        ++convertcmSearchToBED :: CMsearch -> String -> String -> String -> String -> Int -> Bool -> Bool -> Either String Bed+convertcmSearchToBED inputcmsearch inputBrowserSettings trackName trackDescription trackColor inputBedVisibility inputItemRgb sortBed+  | null cmHits = Left "cmsearch file contains no hits"+  | otherwise = Right bed+  where cmHits = cmsearchHits inputcmsearch+        --bedHeader = "browser position " ++ browserPosition ++ "\nbrowser hide all\ntrack name=\"cmsearch hits\" description=\"cmsearch hits\" visibility=2 itemRgb=\"On\"\n"+        bedEntries = map (cmsearchHitToBEDentry trackName trackColor) cmHits+        sortedBedEntries = if sortBed then sortBy orderBedEntry bedEntries else bedEntries+        currentBrowserPosition = T.unpack (chrom firstEntry) ++ ":" ++ show (chromStart firstEntry) ++ "-" ++ show (chromEnd firstEntry)+        firstEntry = head sortedBedEntries+        bed = Bed (T.pack currentBrowserPosition) (T.pack inputBrowserSettings) (T.pack trackName) (T.pack trackDescription) inputBedVisibility inputItemRgb sortedBedEntries++cmsearchHitToBEDentry :: String -> String -> CMsearchHit -> BedEntry+cmsearchHitToBEDentry hitName hitColor cmHit = entry+  where entry = BedEntry  chromosome entrystart entryend (Just (T.pack hitName)) entryscore entrystrand thickstart thickend entrycolor blocks blockSize blockStart+        chromosome = T.pack (B.unpack (hitSequenceHeader cmHit))+        --entryline = L.unpack (hitSequenceHeader cmHit) ++ "\t" ++ entryStart cmHit ++ "\t" ++ entryEnd cmHit++ "\t" ++ (hitName) ++ "\t" ++ "0" ++ "\t" ++ [(hitStrand cmHit)] ++ "\t" ++ show (hitStart cmHit) ++ "\t" ++ show (hitEnd cmHit) ++ "\t" ++ hitColor ++ "\n"+        entrystart = if hitStrand cmHit == '+' then hitStart cmHit else hitEnd cmHit+        entryend = if hitStrand cmHit == '+' then hitEnd cmHit else hitStart cmHit+        entryscore = Just (0 :: Int)+        entrystrand = Just (hitStrand cmHit)+        thickstart = Just entrystart+        thickend = Just entryend+        entrycolor = Just (T.pack hitColor)+        blocks = Just (1 :: Int)+        blockSize = Just [entryend - entrystart]+        blockStart = Just [0 :: Int]+++--cmsearchHitToBEDentry :: String -> String -> CMsearchHit -> String+--cmsearchHitToBEDentry hitName hitColor cmHit = entryline+--  where entryline = L.unpack (hitSequenceHeader cmHit) ++ "\t" ++ entryStart cmHit ++ "\t" ++ entryEnd cmHit++ "\t" ++ (hitName) ++ "\t" ++ "0" ++ "\t" ++ [(hitStrand cmHit)] ++ "\t" ++ show (hitStart cmHit) ++ "\t" ++ show (hitEnd cmHit) ++ "\t" ++ hitColor ++ "\n"+        --entrystart = if (hitStrand cmHit) == '+' then show (hitStart cmHit) else show (hitEnd cmHit)+        --entryend = if (hitStrand cmHit) == '+' then show (hitEnd cmHit) else show (hitStart cmHit)++entryStart :: CMsearchHit -> String+entryStart cmHit+  | hitStrand cmHit == '+' = show (hitStart cmHit)+  | otherwise = show (hitEnd cmHit)++entryEnd :: CMsearchHit -> String+entryEnd cmHit+  | hitStrand cmHit == '+' = show (hitEnd cmHit)+  | otherwise = show (hitStart cmHit)++orderBedEntry :: BedEntry -> BedEntry -> Ordering+orderBedEntry firstHit secondHit+  | start1 > start2 = GT+  | start1 < start2 = LT+  | otherwise = orderBedEntryEnd firstHit secondHit+    where start1 = chromStart firstHit+          start2 = chromStart secondHit++orderBedEntryEnd :: BedEntry -> BedEntry -> Ordering+orderBedEntryEnd firstHit secondHit+  | end1 > end2 = GT+  | end1 < end2 = LT+  | otherwise = EQ+    where end1 = chromEnd firstHit+          end2 = chromEnd secondHit
RNAlien.cabal view
@@ -1,48 +1,49 @@ name:                RNAlien-version:             1.3.7+version:             1.6.0 synopsis:            Unsupervized construction of RNA family models description:         RNAlien is a tool for automatic construction of RNAfamily models from a single sequence.                      .                      It is available as a commandline tool, for testing or construction of few sequences the webservice can be used.                      .                      The source code of RNAlien, as well as the webserver is open source and available via GitHub (License GPL-3):-		     .-		     * <https://github.com/eggzilla/RNAlien RNAlien>-		     .-		     * <https://github.com/eggzilla/AlienServer AlienServer>                      .+                     * <https://github.com/eggzilla/RNAlien RNAlien>+                     .+                     * <https://github.com/eggzilla/AlienServer AlienServer>+                     .                      TaxonomyTools which can be used to visualise the organisms included in a RNAlien result can be found here (License GPL-3):-		     .-		     * <https://github.com/eggzilla/TaxonomyTools TaxonomyTools-Github>-		     .-		     * <https://hackage.haskell.org/package/Taxonomy TaxonomyTools-Hackage>                      .+                     * <https://github.com/eggzilla/TaxonomyTools TaxonomyTools-Github>+                     .+                     * <https://hackage.haskell.org/package/Taxonomy TaxonomyTools-Hackage>+                     .                      For instruction how to use RNAlien please see the <http://rna.tbi.univie.ac.at/rnalien/help Help page>.                      .                      Dependencies:-		     .+                     .                      * <http://infernal.janelia.org/ Infernal>-		     .-		     * <http://www.bioinf.uni-freiburg.de/Software/LocARNA/#download Locarna>-		     .-		     * <https://www.tbi.univie.ac.at/~wash/RNAz/ RNAz>                      .-                     * <http://wash.github.io/rnacode/ RNAcode>                        -		     .-		     * <http://www.tbi.univie.ac.at/RNA/index.html#download ViennaRNA package>+                     * <http://www.bioinf.uni-freiburg.de/Software/LocARNA/#download Locarna>                      .+                     * <https://www.tbi.univie.ac.at/~wash/RNAz/ RNAz>+                     .+                     * <http://wash.github.io/rnacode/ RNAcode>+                     .+                     * <http://www.tbi.univie.ac.at/RNA/index.html#download ViennaRNA package>+                     .                      Installation via cabal-install:                      .                      > cabal install RNAlien-		     + license:             GPL-3 license-file:        LICENSE author:              Florian Eggenhofer-maintainer:          egg@tbi.univie.ac.at--- copyright:           +maintainer:          egg@informatik.uni-freiburg.de+copyright:           Florian Eggenhofer category:            Bioinformatics build-type:          Simple-cabal-version:       >=1.8+cabal-version:       >= 1.10.0+tested-with:         GHC == 8.4.4  source-repository head   type:     git@@ -50,40 +51,51 @@  source-repository this   type:     git-  location: https://github.com/eggzilla/RNAlien/tree/1.3.7-  tag:      1.3.7-                     +  location: https://github.com/eggzilla/RNAlien/tree/1.6.0+  tag:      1.6.0+ executable RNAlien-  Hs-Source-Dirs:      ./src/Bio/-  main-is:	       RNAlien.hs   -  ghc-options:         -Wall -  build-depends:       base >=4.5 && <5, cmdargs, directory, biofasta, random, biocore, containers, RNAlien, time, either-unwrap, filepath+  Hs-Source-Dirs:      ./Biobase/+  main-is:	           RNAlien.hs+  ghc-options:         -Wall+  default-language:    Haskell2010+  other-modules:       Paths_RNAlien+  build-depends:       base >=4.5 && <5, cmdargs, directory,+                       random, containers, RNAlien, time, either-unwrap, filepath,+                       BiobaseFasta == 0.3.0.*  executable RNAlienStatistics-  Hs-Source-Dirs:      ./src/Bio/+  Hs-Source-Dirs:      ./Biobase/   main-is:             RNAlienStatistics.hs-  ghc-options:         -Wall -  build-depends:       base >=4.5 && <5, cmdargs, cassava, vector, process, bytestring, either-unwrap, RNAlien, directory, biofasta, biocore, split, filepath, ViennaRNAParser>=1.3.2+  ghc-options:         -Wall+  default-language:    Haskell2010+  other-modules:       Paths_RNAlien+  build-depends:       base >=4.5 && <5, cmdargs, cassava, vector, process, bytestring, either-unwrap, RNAlien, directory, split, filepath, ViennaRNAParser>=1.3.2, BiobaseFasta == 0.3.0.*, BiobaseTypes == 0.2.0.*  executable cmsearchToBed-  Hs-Source-Dirs:      ./src/Bio/+  Hs-Source-Dirs:      ./Biobase/   main-is:             cmsearchToBED.hs-  ghc-options:         -Wall +  ghc-options:         -Wall+  default-language:    Haskell2010+  other-modules:       Paths_RNAlien   build-depends:       base >=4.5 && <5, cmdargs, either-unwrap, RNAlien, bytestring, text  executable RNAcentralHTTPRequest-  Hs-Source-Dirs:      ./src/Bio/+  Hs-Source-Dirs:      ./Biobase/   main-is:             RNAcentralHTTPRequest.hs-  ghc-options:         -Wall +  ghc-options:         -Wall+  default-language:    Haskell2010+  other-modules:       Paths_RNAlien   build-depends:       base >=4.5 && <5, cmdargs, either-unwrap, RNAlien-  + Library-  Hs-Source-Dirs:      ./src/+  Hs-Source-Dirs:      .   ghc-options:         -Wall -fno-warn-unused-do-bind-  build-depends:       base >=4.5 && <5, cmdargs, ViennaRNAParser>=1.3.2, process, directory, blastxml>=0.3.2, biofasta, parsec, random, BlastHTTP>=1.2.1, biocore, bytestring, Taxonomy >= 1.0.2, either-unwrap, containers, ClustalParser>=1.2.1, EntrezHTTP>=1.0.3, vector, edit-distance, cassava, matrix, hierarchical-clustering, filepath, HTTP, http-conduit, hxt, network, aeson, text, transformers, pureMD5, http-types, text-metrics-  Exposed-Modules:     Bio.RNAlienData-                       Bio.RNAlienLibrary-                       Bio.RNAcentralHTTP-                       Bio.InfernalParser--+  default-language:    Haskell2010+  build-depends:       base >=4.5 && <5, cmdargs, ViennaRNAParser>=1.3.2, process, directory,+                       parsec, random, bytestring, Taxonomy >= 1.0.3, either-unwrap, containers, ClustalParser>=1.2.1, vector, edit-distance, cassava, matrix, hierarchical-clustering, filepath, HTTP, http-conduit, hxt, network<=2.8.0.0, aeson, text, transformers, pureMD5, http-types, text-metrics,+                       BiobaseTypes == 0.2.0.*, BiobaseFasta == 0.3.0.* , BiobaseBlast == 0.3.0.*, BlastHTTP >= 1.4.0, BiobaseHTTP == 1.1.0+  Exposed-Modules:     Biobase.RNAlien.Types+                       Biobase.RNAlien.Library+                       Biobase.RNAlien.RNAcentralHTTP+                       Biobase.RNAlien.InfernalParser
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
− src/Bio/InfernalParser.hs
@@ -1,340 +0,0 @@--- | This module contains parsing functions for Infernal programs--module Bio.InfernalParser (-                           module Bio.RNAlienData,-                           readCMSearch,-                           readCMSearches,-                           parseCMSearch,-                           parseCMSearches,-                           parseCMstat,-                           readCMstat-                           )-where--import Text.ParserCombinators.Parsec-import Bio.RNAlienData-import qualified Data.ByteString.Lazy.Char8 as L-import qualified Control.Exception.Base as CE---- | parse from input filePath              -parseCMSearch :: String -> Either ParseError CMsearch-parseCMSearch = parse genParserCMSearch "parseCMsearch"---- | parse from input filePath              -parseCMSearches :: String -> Either ParseError CMsearch-parseCMSearches = parse genParserCMSearches "parseCMsearch"---- | parse from input filePath                      -readCMSearch :: String -> IO (Either ParseError CMsearch)-readCMSearch filePath = do-  parsedFile <- parseFromFile genParserCMSearch filePath-  CE.evaluate parsedFile---- | parse from input filePath                      -readCMSearches :: String -> IO (Either ParseError CMsearch)-readCMSearches filePath = do-  parsedFile <- parseFromFile genParserCMSearches filePath-  CE.evaluate parsedFile--genParserCMSearches :: GenParser Char st CMsearch-genParserCMSearches = do-  string "# cmsearch :: search CM(s) against a sequence database"-  newline-  string "# INFERNAL "-  many1 (noneOf "\n")-  newline-  string "# Copyright (C) 201"-  many1 (noneOf "\n")-  newline-  string "# Freely distributed under the GNU General Public License (GPLv3)."-  newline-  string "# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"-  newline-  string "# query CM file:"-  many1 space-  queryCMfile' <- many1 (noneOf "\n")-  newline-  string "# target sequence database:"-  many1 space-  targetSequenceDatabase' <- many1 (noneOf "\n")-  newline-  optional (try (genParserCMsearchHeaderField "# CM configuration"))-  optional (try (genParserCMsearchHeaderField "# database size is set to"))-  optional (try (genParserCMsearchHeaderField "# truncated sequence detection"))-  string "# number of worker threads:"-  many1 space-  numberOfWorkerThreads' <- many1 (noneOf "\n")-  newline-  string "# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"-  newline-  optional newline-  cmSearchesHits <- many1 (try genParserMultipleCMSearch)-  optional (string "[ok]\n")-  eof-  return $ CMsearch queryCMfile' targetSequenceDatabase' numberOfWorkerThreads' (concat cmSearchesHits)--genParserCMSearch :: GenParser Char st CMsearch-genParserCMSearch = do-  string "# cmsearch :: search CM(s) against a sequence database"-  newline-  string "# INFERNAL "-  many1 (noneOf "\n")-  newline-  string "# Copyright (C) 201"-  many1 (noneOf "\n")-  newline-  string "# Freely distributed under the GNU General Public License (GPLv3)."-  newline-  string "# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"-  newline-  string "# query CM file:"-  many1 space-  queryCMfile' <- many1 (noneOf "\n")-  newline-  string "# target sequence database:"-  many1 space-  targetSequenceDatabase' <- many1 (noneOf "\n")-  newline-  optional (try (genParserCMsearchHeaderField "# CM configuration"))-  optional (try (genParserCMsearchHeaderField "# database size is set to"))-  optional (try (genParserCMsearchHeaderField "# truncated sequence detection"))-  string "# number of worker threads:"-  many1 space-  numberOfWorkerThreads' <- many1 (noneOf "\n")-  newline-  string "# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"-  newline-  optional newline-  string "Query:"-  many1 (noneOf "\n")-  newline-  optional (try (genParserCMsearchHeaderField "Accession"))-  optional (try (genParserCMsearchHeaderField "Description"))-  string "Hit scores:"-  newline-  choice  [try (string " rank"), try (string "  rank") , try (string "   rank"), try (string "    rank"),try (string "     rank"),try (string "      rank")]-  many1 space-  string "E-value"-  many1 space-  string "score"-  many1 space-  string "bias"-  many1 space-  string "sequence"-  many1 space-  string "start"-  many1 space-  string "end"-  many1 space-  string "mdl"-  many1 space-  string "trunc"-  many1 space-  string "gc"-  many1 space-  string "description"-  newline-  string " -"-  many1 (try (oneOf " -"))-  newline-  optional (try (string " ------ inclusion threshold ------"))-  many newline-  hitScores' <- many (try genParserCMsearchHit) --`endBy` (try (string "Hit alignments:"))-  optional (try genParserCMsearchEmptyHit)-  -- this is followed by hit alignments and internal cmsearch statistics which are not parsed-  many anyChar-  eof-  return $ CMsearch queryCMfile' targetSequenceDatabase' numberOfWorkerThreads' hitScores'---- | Parsing function for CMSearches with multiple querymodels in one modelfile, e.g. clans-genParserMultipleCMSearch :: GenParser Char st [CMsearchHit]-genParserMultipleCMSearch = do-  --optional newline-  --optional string "//"-  string "Query:"-  many1 (noneOf "\n")-  newline-  optional (try (genParserCMsearchHeaderField "Accession"))-  optional (try (genParserCMsearchHeaderField "Description"))-  string "Hit scores:"-  newline-  choice  [try (string " rank"), try (string "  rank") , try (string "   rank"), try (string "    rank"),try (string "     rank"),try (string "      rank")]-  many1 space-  string "E-value"-  many1 space-  string "score"-  many1 space-  string "bias"-  many1 space-  string "sequence"-  many1 space-  string "start"-  many1 space-  string "end"-  many1 space-  string "mdl"-  many1 space-  string "trunc"-  many1 space-  string "gc"-  many1 space-  string "description"-  newline-  string " -"-  many1 (try (oneOf " -"))-  newline-  optional (try (string " ------ inclusion threshold ------"))-  many newline-  hitScores' <- many (try genParserCMsearchHit) --`endBy` (try (string "Hit alignments:"))-  optional (try genParserCMsearchEmptyHit)-  -- this is followed by hit alignments and internal cmsearch statistics which are not parsed-  --many anyChar-  manyTill anyChar (try (string "//\n"))-  return hitScores'--genParserCMsearchHeaderField :: String -> GenParser Char st String-genParserCMsearchHeaderField fieldname = do-  string (fieldname ++ ":")-  many1 space-  many1 (noneOf "\n")-  newline-  return []--genParserCMsearchEmptyHit :: GenParser Char st [CMsearchHit]-genParserCMsearchEmptyHit = do-  string "   [No hits detected that satisfy reporting thresholds]"-  newline-  optional (try newline)-  return []--genParserCMsearchHit :: GenParser Char st CMsearchHit-genParserCMsearchHit = do-  many1 space-  string "("-  hitRank' <- many1 digit-  string ")"-  many1 space-  hitSignificant' <- choice [char '!', char '?']-  many1 space-  hitEValue' <- many1 (oneOf "0123456789.e-")-  many1 space-  hitScore'  <- many1 (oneOf "0123456789.e-")-  many1 space-  hitBias' <- many1 (oneOf "0123456789.e-")-  many1 space-  hitSequenceHeader' <- many1 (noneOf " ")-  many1 space-  hitStart' <- many1 digit-  many1 space-  hitEnd' <- many1 digit-  many1 space-  hitStrand' <- choice [char '+', char '-', char '.']-  many1 space-  hitModel' <- many1 letter-  many1 space-  hitTruncation' <- many1 (choice [alphaNum, char '\''])-  many1 space-  hitGCcontent' <- many1 (oneOf "0123456789.e-")-  many1 space-  hitDescription' <- many1 (noneOf "\n")-  newline-  optional (try (string " ------ inclusion threshold ------"))-  optional (try newline)-  return $ CMsearchHit (readInt hitRank') hitSignificant' (readDouble hitEValue') (readDouble hitScore') (readDouble hitBias') (L.pack hitSequenceHeader') (readInt hitStart') (readInt hitEnd') hitStrand' (L.pack hitModel') (L.pack hitTruncation') (readDouble hitGCcontent') (L.pack hitDescription')---- | parse from input filePath              -parseCMstat :: String -> Either ParseError CMstat-parseCMstat = parse genParserCMstat "parseCMstat"---- | parse from input filePath                      -readCMstat :: String -> IO (Either ParseError CMstat)-readCMstat filePath = do-  parsedFile <- parseFromFile genParserCMstat filePath-  CE.evaluate parsedFile--genParserCMstat :: GenParser Char st CMstat-genParserCMstat = do-  string "# cmstat :: display summary statistics for CMs"-  newline-  string "# INFERNAL "-  many1 (noneOf "\n")-  newline-  string "# Copyright (C) 201"-  many1 (noneOf "\n")-  newline-  string "# Freely distributed under the GNU General Public License (GPLv3)."-  newline-  string "# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"-  newline-  char '#'-  many1 (char ' ')-  string "rel entropy"-  newline-  char '#'-  many1 (char ' ')-  many1 (char '-')-  newline-  char '#'-  many1 space-  string "idx"-  many1 space-  string "name"-  many1 space-  string "accession"-  many1 space-  string "nseq"-  many1 space-  string "eff_nseq"-  many1 space-  string "clen"-  many1 space-  string "W"-  many1 space-  string "bps"-  many1 space-  string "bifs"-  many1 space-  string "model"-  many1 space-  string "cm"-  many1 space-  string "hmm"-  newline-  string "#"-  many1 (try (oneOf " -"))-  newline-  many1 space-  _statIndex <- many1 digit-  many1 space-  _statName <- many1 letter-  many1 space-  _statAccession <- many1 (noneOf " ")-  many1 space-  _statSequenceNumber <- many1 digit-  many1 space-  _statEffectiveSequences <- many1 (oneOf "0123456789.e-")-  many1 space-  _statConsensusLength <- many digit-  many1 space-  _statW <- many1 digit-  many1 space-  _statBasepaires <- many1 digit-  many1 space-  _statBifurcations <- many1 digit-  many1 space-  _statModel <- many1 letter-  many1 space-  _relativeEntropyCM <- many1 (oneOf "0123456789.e-")-  many1 space-  _relativeEntropyHMM <- many1 (oneOf "0123456789.e-")-  newline-  char '#'-  newline-  eof-  return $ CMstat (readInt _statIndex) _statName _statAccession (readInt _statSequenceNumber) (readDouble _statEffectiveSequences) (readInt _statConsensusLength) (readInt _statW) (readInt _statBasepaires) (readInt _statBifurcations) _statModel (readDouble _relativeEntropyCM) (readDouble _relativeEntropyHMM)---   -readInt :: String -> Int-readInt = read--readDouble :: String -> Double-readDouble = read
− src/Bio/RNAcentralHTTP.hs
@@ -1,126 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--{-# LANGUAGE DeriveGeneric #-}---- | Interface for the RNAcentral REST webservice.---   -module Bio.RNAcentralHTTP (rnaCentralHTTP,-                      buildSequenceViaMD5Query,-                      buildStringViaMD5Query,-                      getRNACentralEntries,-                      showRNAcentralAlienEvaluation,-                      RNAcentralEntryResponse(..),-                      RNAcentralEntry(..)-                      ) where--import Network.HTTP.Conduit-import qualified Data.ByteString.Lazy.Char8 as L8-import Network-import Control.Concurrent-import Data.Text-import Data.Aeson-import GHC.Generics-import qualified Data.Digest.Pure.MD5 as M-import Bio.Core.Sequence-import Bio.Sequence.Fasta-import Data.Either----Datatypes--- | Data structure for RNAcentral entry response-data RNAcentralEntryResponse = RNAcentralEntryResponse-  {-    count :: Int,-    next :: Maybe Text,-    previous :: Maybe Text,-    results :: [RNAcentralEntry]-  }-  deriving (Show, Eq, Generic)--instance ToJSON RNAcentralEntryResponse where-  toJSON = genericToJSON defaultOptions-  --toEncoding = genericToEncoding defaultOptions--instance FromJSON RNAcentralEntryResponse--data RNAcentralEntry = RNAcentralEntry-  {-    url :: Text,-    rnacentral_id :: Text,-    md5 :: Text,-    sequence :: Text,-    length :: Int,-    xrefs :: Text,-    publications :: Text-  }-  deriving (Show, Eq, Generic)--instance ToJSON RNAcentralEntry where-  toJSON = genericToJSON defaultOptions-  --toEncoding = genericToEncoding defaultOptions--instance FromJSON RNAcentralEntry---- | Send query and parse return XML -startSession :: String -> IO (Either String RNAcentralEntryResponse)-startSession query' = do-  requestXml <- withSocketsDo-      $ sendQuery query'-  --putStr (L8.unpack requestXml)-  let eitherErrorResponse = eitherDecode requestXml :: Either String RNAcentralEntryResponse-  return eitherErrorResponse---- | Send query and return response XML-sendQuery :: String -> IO L8.ByteString-sendQuery query' = do-   let address = "http://rnacentral.org/api/v1/rna/"-   let request = address ++ query'-   --putStrLn request-   simpleHttp request---- | Function for querying the RNAcentral REST interface.-rnaCentralHTTP :: String -> IO (Either String RNAcentralEntryResponse)-rnaCentralHTTP query' =-  startSession query'---- | Function for delayed queries to the RNAcentral REST interface. Enforces the maximum 20 requests per second policy.-delayedRNACentralHTTP :: String -> IO (Either String RNAcentralEntryResponse)-delayedRNACentralHTTP query' = do-  threadDelay 55000-  startSession query'--getRNACentralEntries :: [String] -> IO [Either String RNAcentralEntryResponse]-getRNACentralEntries queries = do-  mapM delayedRNACentralHTTP queries----Build a query from a input sequence-buildSequenceViaMD5Query :: Sequence -> String-buildSequenceViaMD5Query s = qString-  where querySequence = unSD (seqdata s)-        querySequenceUreplacedwithT = L8.map bsreplaceUT querySequence-        querySequenceU2Twolb = L8.filter ((/= '\n')) querySequenceUreplacedwithT-        md5Sequence = M.md5 querySequenceU2Twolb-        qString = "?md5=" ++ show md5Sequence----Build a query from a input string-buildStringViaMD5Query :: String -> String-buildStringViaMD5Query s = qString-  where querySequenceUreplacedwithT = L8.map bsreplaceUT (L8.pack s)-        querySequenceU2Twolb = L8.filter ((/= '\n')) querySequenceUreplacedwithT-        md5Sequence = M.md5 querySequenceU2Twolb-        qString = "?md5=" ++ show md5Sequence--showRNAcentralAlienEvaluation :: [Either String RNAcentralEntryResponse] -> String-showRNAcentralAlienEvaluation responses = output-  where resultEntries = Prelude.concatMap results (rights responses)-        resulthead = "rnacentral_id\tmd5\tlength\n"-        resultentries = Prelude.concatMap showRNAcentralAlienEvaluationLine resultEntries-        output = if Prelude.null resultentries then "No matching sequences found in RNAcentral\n" else resulthead ++ resultentries--showRNAcentralAlienEvaluationLine :: RNAcentralEntry -> String-showRNAcentralAlienEvaluationLine entry = unpack (rnacentral_id entry) ++ "\t" ++ unpack (md5 entry) ++ "\t" ++ show (Bio.RNAcentralHTTP.length entry) ++"\n"--bsreplaceUT :: Char -> Char-bsreplaceUT a-  | a == 'U' = 'T'-  | otherwise = a-
− src/Bio/RNAcentralHTTPRequest.hs
@@ -1,26 +0,0 @@-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE DeriveDataTypeable #-}---- | RNAcentralHTTPRequest---   Testcommand: dist/build/RNAcentralHTTPRequest/RNAcentralHTTPRequest -i ATACTTACCTGGCACAGGGGATACCACGATCACCAAGGTGGTTCCCCCAAGACGAGGCTCACCATTGCACTCCGGTGGCGCTGACCCTTGCAATGACCCCAAATGTGGGTTACTCGGGTGTGTAATTTCTGTTAGCTGGGGACTGCGTTCGCGCTTTCCCCTT-module Main where--import System.Console.CmdArgs-import Bio.RNAcentralHTTP--data Options = Options-  { inputSequence :: String-  } deriving (Show,Data,Typeable)--options :: Options-options = Options-  { inputSequence = def &= name "i" &= help "input sequence"-  } &= summary "RNAcentralHTTPRequest" &= help "Florian Eggenhofer 2016" &= verbosity--main :: IO ()-main = do-  Options{..} <- cmdArgs options-  let query = buildStringViaMD5Query inputSequence-  rnacentralentries <- getRNACentralEntries [query]-  print rnacentralentries-
− src/Bio/RNAlien.hs
@@ -1,128 +0,0 @@-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE DeriveDataTypeable #-}---- | Unsupervized construction of RNA family models---   For more information on RNA family models consult <http://>---   Testcommand: dist/build/RNAlien/RNAlien -i ~egg/initialfasta/RybB.fa -c 3 -o /scr/kronos/egg/temp/ > ~egg/Desktop/alieninitialtest-module Main where--import System.Console.CmdArgs-import System.Directory-import Bio.Sequence.Fasta-import Bio.RNAlienData-import Bio.RNAlienLibrary-import Data.Maybe-import Data.Either.Unwrap-import Data.Time-import qualified System.FilePath as FP-import Paths_RNAlien (version)-import Data.Version (showVersion)--data Options = Options-  { inputFastaFilePath :: String,-    outputPath :: String,-    inputTaxId :: Maybe Int,-    inputnSCICutoff :: Maybe Double,-    inputEvalueCutoff :: Maybe Double,-    inputBlastDatabase :: Maybe String,-    lengthFilter :: Bool,-    coverageFilter :: Bool,-    singleHitperTax :: Bool,-    blastSoftmasking :: Bool,-    inputQuerySelectionMethod :: String,-    inputQueryNumber :: Int,-    threads :: Int,-    taxonomyRestriction :: Maybe String,-    sessionIdentificator :: Maybe String,-    performEvaluation :: Bool,-    checkSetup :: Bool-  } deriving (Show,Data,Typeable)--options :: Options-options = Options-  { inputFastaFilePath = def &= name "i" &= help "Path to input fasta file",-    outputPath = def &= name "o" &= help "Path to output directory. Default: current working directory",-    inputTaxId = Nothing &= name "t" &= help "NCBI taxonomy ID number of input RNA organism",-    inputnSCICutoff = Just (1 :: Double) &= name "z" &= help "Only candidate sequences with a normalized structure conservation index (nSCI) higher than this value are accepted. Default: 1",-    inputEvalueCutoff = Just (0.001 :: Double) &= name "e" &= help "Evalue cutoff for cmsearch filtering. Default: 0.001",-    inputBlastDatabase = Just "nt" &= name "b" &= help "Specify name of blast database to use. Default: nt",-    lengthFilter = True &= name "l" &= help "Filter blast hits per genomic length. Default: True",-    coverageFilter = True &= name "a" &= help "Filter blast hits by coverage of at least 80%. Default: True",-    singleHitperTax = False &= name "s" &= help "Only the best blast hit per taxonomic entry is considered. Default: False",-    blastSoftmasking = False &= name "f" &= help "Toggles blast query softmasking, meaning masking of non-conserved regions on the query. Default: False",-    inputQuerySelectionMethod = "filtering" &= name "m" &= help "Method for selection of queries (filtering,clustering). Default: filtering",-    inputQueryNumber = (5 :: Int) &= name "n" &= help "Number of queries used for candidate search. Default: 5",-    threads = 1 &= name "c" &= help "Number of available cpu slots/cores. Default: 1",-    taxonomyRestriction = Nothing &= name "r" &= help "Restrict search space to taxonomic kingdom (bacteria,archea,eukaryia). Default: not set",-    sessionIdentificator = Nothing &= name "d" &= help "Optional session id that is used instead of automatically generated one.",-    performEvaluation = True &= name "x" &= help "Perform evaluation step. Default: True",-    checkSetup = False &= name "g" &= help "Just prints installed tool versions and performs connection check. Default: False"-  } &= summary ("RNAlien " ++ alienVersion) &= help "Florian Eggenhofer, Ivo L. Hofacker, Christian Hoener zu Siederdissen - 2013 - 2017" &= verbosity--main :: IO ()-main = do-  Options{..} <- cmdArgs options-  verboseLevel <- getVerbosity-  let tools = if inputQuerySelectionMethod == "clustering" then ["clustalo","mlocarna","RNAfold","RNAalifold","cmcalibrate","cmstat","cmbuild","RNAz","RNAcode"] else ["mlocarna","RNAfold","RNAalifold","cmcalibrate","cmstat","cmbuild","RNAz","RNAcode"]-  -- Generate SessionID-  sessionId <- createSessionID sessionIdentificator-  timestamp <- getCurrentTime-  currentWorkDirectory <- getCurrentDirectory-  let selectedOutputPath = if null outputPath then currentWorkDirectory else outputPath-  let temporaryDirectoryPath = FP.addTrailingPathSeparator selectedOutputPath ++ sessionId ++ "/"-  createDirectoryIfMissing False temporaryDirectoryPath-  networkCheck <- checkNCBIConnection-  if checkSetup-    then do-      toolsCheck <- checkTools tools inputQuerySelectionMethod temporaryDirectoryPath-      let setupCheckPath = temporaryDirectoryPath ++ "setupCheck"-      let toolCheckResult = either id id toolsCheck-      let networkCheckResult = either id id networkCheck-      writeFile setupCheckPath (toolCheckResult ++ "\n" ++ networkCheckResult ++ "\n")-    else-      if isLeft networkCheck-        then do-          putStrLn ("Error - Could not contact NCBI server: " ++ fromLeft networkCheck ++ "\n")-          logMessage ("Error - Could not contact NCBI server: " ++ fromLeft networkCheck ++ "\n") temporaryDirectoryPath-       else do-           createDirectoryIfMissing False (temporaryDirectoryPath ++ "log")-           -- Create Log files-           writeFile (temporaryDirectoryPath ++ "Log") ("RNAlien " ++ alienVersion ++ "\n")-           writeFile (temporaryDirectoryPath ++ "log/warnings") ("")-           logMessage ("Timestamp: " ++ (show timestamp) ++ "\n") temporaryDirectoryPath-           logMessage ("Temporary Directory: " ++ temporaryDirectoryPath ++ "\n") temporaryDirectoryPath-           inputFasta <- readFasta inputFastaFilePath-           if null inputFasta-             then do-               putStrLn "Error: Input fasta file is empty."-               logMessage "Error: Input fasta file is empty.\n" temporaryDirectoryPath-             else do-               let iterationNumber = 0-               toolsCheck <- checkTools tools inputQuerySelectionMethod temporaryDirectoryPath-               if isLeft toolsCheck-                 then do-                   putStrLn ("Error - Not all required tools could be found in $PATH: " ++ fromLeft toolsCheck ++ "\n")-                   logMessage ("Error - Not all required tools could be found in $PATH: " ++ fromLeft toolsCheck ++ "\n") temporaryDirectoryPath-                 else do-                   logToolVersions inputQuerySelectionMethod temporaryDirectoryPath-                   let inputSequence = reformatFasta (head inputFasta)-                   initialTaxId <- setInitialTaxId inputBlastDatabase temporaryDirectoryPath inputTaxId inputSequence-                   let checkedTaxonomyRestriction = checkTaxonomyRestriction taxonomyRestriction-                   let staticOptions = StaticOptions temporaryDirectoryPath sessionId (fromJust inputnSCICutoff) inputTaxId singleHitperTax inputQuerySelectionMethod inputQueryNumber lengthFilter coverageFilter blastSoftmasking threads inputBlastDatabase checkedTaxonomyRestriction (setVerbose verboseLevel)-                   let initialization = ModelConstruction iterationNumber inputSequence [] initialTaxId Nothing (fromJust inputEvalueCutoff) False [] []-                   logMessage (show initialization) temporaryDirectoryPath-                   modelConstructionResults <- modelConstructer staticOptions initialization-                   let resultTaxonomyRecordsCSVTable = constructTaxonomyRecordsCSVTable modelConstructionResults-                   writeFile (temporaryDirectoryPath ++ "result.csv") resultTaxonomyRecordsCSVTable-                   if performEvaluation-                     then do-                       resultEvaluation <- evaluateConstructionResult staticOptions modelConstructionResults-                       appendFile (temporaryDirectoryPath ++ "Log") resultEvaluation-                       resultSummary modelConstructionResults staticOptions-                       writeFile (temporaryDirectoryPath ++ "done") ""-                     else do-                       resultSummary modelConstructionResults staticOptions-                       writeFile (temporaryDirectoryPath ++ "done") ""--alienVersion :: String-alienVersion = showVersion version
− src/Bio/RNAlienData.hs
@@ -1,144 +0,0 @@--- | This module contains data structures for RNAlien--module Bio.RNAlienData where--import qualified Data.ByteString.Lazy.Char8 as L-import Bio.Core.Sequence-import Bio.Sequence.Fasta-import Bio.Taxonomy---- | Static construction options-data StaticOptions = StaticOptions-  { tempDirPath :: String,-    sessionID :: String,-    nSCICutoff :: Double,-    userTaxId :: Maybe Int,-    singleHitperTaxToggle :: Bool,-    querySelectionMethod :: String,-    queryNumber :: Int,-    lengthFilterToggle :: Bool,-    coverageFilterToggle :: Bool,-    blastSoftmaskingToggle :: Bool,-    cpuThreads :: Int,-    blastDatabase :: Maybe String,-    taxRestriction :: Maybe String,-    verbositySwitch :: Bool-  } deriving (Show)---- | Keeps track of model construction -data ModelConstruction = ModelConstruction-  { iterationNumber :: Int,-    inputFasta :: Sequence,-    taxRecords :: [TaxonomyRecord],-    --Taxonomy ID of the highest node in taxonomic subtree used in search-    upperTaxonomyLimit :: Maybe Int,-    taxonomicContext :: Maybe Taxon,-    evalueThreshold :: Double,-    alignmentModeInfernal :: Bool,-    selectedQueries :: [Sequence],-    potentialMembers :: [SearchResult]-  }--instance Show ModelConstruction where-  show (ModelConstruction _iterationNumber _inputFasta _taxRecords _upperTaxonomyLimit _taxonomicContext _evalueThreshold _alignmentModeInfernal _selectedQueries _potentialMembers) = a ++ b ++ c ++ d ++ e ++ g ++ h ++ i-    where a = "Modelconstruction iteration: " ++ show _iterationNumber ++ "\n"-          b = "Input fasta:\n" ++ L.unpack (unSL (seqheader _inputFasta))  ++ "\n" ++ L.unpack (unSD (seqdata _inputFasta)) ++ "\n"-          c = show _taxRecords-          d = "Upper taxonomy limit: " ++ maybe "not set" show _upperTaxonomyLimit ++ "\n"-          e = "Taxonomic Context: " ++  maybe "not set" show _taxonomicContext ++ "\n"-          g = "Evalue cutoff: " ++ show _evalueThreshold ++ "\n"-          h = "Selected queries: \n" ++ concatMap show _selectedQueries-          i = "Potential Members: \n" ++ concatMap show _potentialMembers--data TaxonomyRecord = TaxonomyRecord-  { recordTaxonomyId :: Int,-    sequenceRecords :: [SequenceRecord]-  }--instance Show TaxonomyRecord where-  show (TaxonomyRecord _recordTaxonomyId _sequenceRecords) = a ++ b-    where a = "TaxonomyRecord TaxonomyId: " ++ show _recordTaxonomyId ++ "\n"-          b = show _sequenceRecords--data SequenceRecord = SequenceRecord-  { --Sequence consisting of SeqLabel, and SeqData-    nucleotideSequence :: Sequence,-    -- 0 is unaligned, number is the iteration the sequence has been included into the alignment-    aligned  :: Int,-    recordDescription :: L.ByteString-  }--instance Show SequenceRecord where-  show (SequenceRecord _nucleotideSequence _aligned _recordDescription) = a ++ b ++ c-    where a = "Record Description: " ++ L.unpack _recordDescription ++ "\n"-          b = "Aligned in iteration: " ++ show _aligned ++ "\n"-          c = "Sequence:" ++ show _nucleotideSequence ++ "\n"--- |  -data CMsearch = CMsearch-  { queryCMfile :: String,-    targetSequenceDatabase :: String,-    numberOfWorkerThreads :: String,-    cmsearchHits :: [CMsearchHit]---    hitAlignments :: [CMsearchHitAlignment]---    internalCMPipelineStatisticsSummary                 -  } deriving (Show, Eq, Read)---- |  -data CMsearchHit = CMsearchHit-  { hitRank :: Int,-    hitSignificance :: Char,-    hitEvalue :: Double,-    hitScore :: Double,-    hitBias :: Double,-    hitSequenceHeader :: L.ByteString,-    hitStart :: Int,-    hitEnd :: Int,-    hitStrand :: Char,-    hitModel :: L.ByteString,-    hitTruncation :: L.ByteString,-    hitGCContent :: Double,-    hitDescription :: L.ByteString-  } deriving (Show, Eq, Read)--data SearchResult = SearchResult-  { candidates :: [(Sequence,Int,L.ByteString)],-    blastDatabaseSize :: Maybe Double-  }--instance Show SearchResult where-  show (SearchResult _candidates _blastDatabaseSize) = a ++ b-    where a = "SearchResults :\n " ++ concatMap show _candidates ++ "\n"-          b = "BlastDb Size: " ++ show _blastDatabaseSize ++ "\n"---- |  -data CMstat = CMstat-  { statIndex :: Int,-    statName :: String,-    statAccession :: String,-    statSequenceNumber :: Int,-    statEffectiveSequences :: Double,-    statConsensusLength :: Int,-    -- W The expected maximum length of a hit to the model.-    statW :: Int,-    statBasepairs :: Int,-    statBifurcations :: Int,-    statModel :: String,-    relativeEntropyCM :: Double,-    relativeEntropyHMM :: Double-  } deriving (Eq, Read)--instance Show CMstat where-  show (CMstat _statIndex _statName _statAccession _statSequenceNumber _statEffectiveSequences _statConsensusLength _statW _statBasepairs _statBifurcations _statModel _relativeEntropyCM _relativeEntropyHMM) = a ++ b ++ c ++ d ++ e ++ f ++ g ++ h ++ i ++ j ++ k ++ l-    where a = "CMstat - covariance model statistics:\nIndex: " ++ show _statIndex ++ "\n"-          b = "Name: " ++ show _statName ++ "\n"-          c = "Accession: " ++ show _statAccession ++ "\n"-          d = "Sequence Number: " ++ show _statSequenceNumber ++ "\n"-          e = "Effective Sequences: " ++ show _statEffectiveSequences ++ "\n"-          f = "Consensus length: " ++ show _statConsensusLength ++ "\n"-          g = "Expected maximum hit-length: " ++ show _statW ++ "\n"-          h = "Basepairs: " ++ show _statBasepairs ++ "\n"-          i = "Bifurcations: " ++ show _statBifurcations ++ "\n"-          j = "Modeltype: " ++ show _statModel ++ "\n"-          k = "Relative Entropy CM: " ++ show _relativeEntropyCM ++ "\n"-          l = "Relative Entropy HMM: " ++ show _relativeEntropyHMM ++ "\n"-
− src/Bio/RNAlienLibrary.hs
@@ -1,1904 +0,0 @@--- | This module contains functions for RNAlien-{-# LANGUAGE RankNTypes #-}-module Bio.RNAlienLibrary (-                           module Bio.RNAlienData,-                           createSessionID,-                           logMessage,-                           logEither,-                           modelConstructer,-                           constructTaxonomyRecordsCSVTable,-                           resultSummary,-                           setVerbose,-                           logToolVersions,-                           checkTools,-                           systemCMsearch,-                           readCMSearch,-                           readCMSearches,-                           compareCM,-                           parseCMSearch,-                           cmSearchsubString,-                           setInitialTaxId,-                           evaluateConstructionResult,-                           readCMstat,-                           parseCMstat,-                           checkNCBIConnection,-                           preprocessClustalForRNAz,-                           preprocessClustalForRNAzExternal,-                           preprocessClustalForRNAcodeExternal,-                           rnaZEvalOutput,-                           reformatFasta,-                           checkTaxonomyRestriction,-                           evaluePartitionTrimCMsearchHits-                           )-where--import System.Process-import qualified System.FilePath as FP-import Text.ParserCombinators.Parsec-import Data.List-import Data.Char-import Bio.Core.Sequence-import Bio.Sequence.Fasta-import Bio.BlastXML-import Bio.ClustalParser-import Data.Int (Int16)-import Bio.RNAlienData-import qualified Data.ByteString.Lazy.Char8 as L-import qualified Data.ByteString.Char8 as B-import Bio.Taxonomy-import Data.Either.Unwrap-import Data.Maybe-import Bio.EntrezHTTP-import System.Exit-import Data.Either (lefts,rights,Either)-import qualified Text.EditDistance as ED-import qualified Data.Vector as V-import Control.Concurrent-import System.Random-import Data.Csv-import Data.Matrix-import Bio.BlastHTTP-import Data.Clustering.Hierarchical-import System.Directory-import System.Console.CmdArgs-import qualified Control.Exception.Base as CE-import Bio.RNAfoldParser-import Bio.RNAalifoldParser-import Bio.RNAzParser-import qualified Network.HTTP.Conduit as N-import Network.HTTP.Types.Status-import qualified Bio.RNAcodeParser as RC-import qualified Bio.RNAcentralHTTP as RCH-import Bio.InfernalParser-import qualified Data.Text as T-import qualified Data.Text.IO as TI-import qualified Data.Text.Encoding as DTE-import qualified Data.Text.Lazy.Encoding as E-import qualified Data.Text.Lazy as TL-import qualified Data.Text.Lazy.IO as TIO-import Text.Printf-import qualified Data.Text.Metrics as TM-import Control.Monad-import Control.Arrow---- | Initial RNA family model construction - generates iteration number, seed alignment and model-modelConstructer :: StaticOptions -> ModelConstruction -> IO ModelConstruction-modelConstructer staticOptions modelConstruction = do-  logMessage ("Iteration: " ++ show (iterationNumber modelConstruction) ++ "\n") (tempDirPath staticOptions)-  iterationSummary modelConstruction staticOptions-  let currentIterationNumber = iterationNumber modelConstruction-  let foundSequenceNumber = length (concatMap sequenceRecords (taxRecords modelConstruction))-  --extract queries-  let queries = extractQueries foundSequenceNumber modelConstruction-  logVerboseMessage (verbositySwitch staticOptions) ("Queries:" ++ show queries ++ "\n") (tempDirPath staticOptions)-  let iterationDirectory = tempDirPath staticOptions ++ show currentIterationNumber ++ "/"-  let maybeLastTaxId = extractLastTaxId (taxonomicContext modelConstruction)-  Control.Monad.when (isNothing maybeLastTaxId) $ logMessage ("Lineage: Could not extract last tax id \n") (tempDirPath staticOptions)-  --If highest node in linage was used as upper taxonomy limit, taxonomic tree is exhausted-  if maybe True (\uppertaxlimit -> maybe True (\lastTaxId -> uppertaxlimit /= lastTaxId) maybeLastTaxId) (upperTaxonomyLimit modelConstruction)-     then do-       createDirectory iterationDirectory-       let (upperTaxLimit,lowerTaxLimit) = setTaxonomicContextEntrez currentIterationNumber (taxonomicContext modelConstruction) (upperTaxonomyLimit modelConstruction)-       logVerboseMessage (verbositySwitch staticOptions) ("Upper taxonomy limit: " ++ show upperTaxLimit ++ "\n " ++ "Lower taxonomy limit: "++ show lowerTaxLimit ++ "\n") (tempDirPath staticOptions)-       --search queries-       let expectThreshold = setBlastExpectThreshold modelConstruction-       searchResults <- catchAll (searchCandidates staticOptions Nothing currentIterationNumber upperTaxLimit lowerTaxLimit expectThreshold queries)-                        (\e -> do logWarning ("Warning: Search results iteration" ++ show (iterationNumber modelConstruction) ++ " - exception: " ++ show e) (tempDirPath staticOptions)-                                  return (SearchResult [] Nothing))-       currentTaxonomicContext <- getTaxonomicContextEntrez upperTaxLimit (taxonomicContext modelConstruction)-       if null (candidates searchResults)-         then-            alignmentConstructionWithoutCandidates currentTaxonomicContext upperTaxLimit staticOptions modelConstruction-         else-            alignmentConstructionWithCandidates currentTaxonomicContext upperTaxLimit searchResults staticOptions modelConstruction-     else do-       logMessage "Message: Modelconstruction complete: Out of queries or taxonomic tree exhausted\n" (tempDirPath staticOptions)-       modelConstructionResult staticOptions modelConstruction--catchAll :: IO a -> (CE.SomeException -> IO a) -> IO a-catchAll = CE.catch--setInitialTaxId :: Maybe String -> String -> Maybe Int -> Sequence -> IO (Maybe Int)-setInitialTaxId inputBlastDatabase tempdir inputTaxId inputSequence =-  if (isNothing inputTaxId)-    then do-      initialTaxId <- findTaxonomyStart inputBlastDatabase tempdir inputSequence-      return (Just initialTaxId)-    else do-        return inputTaxId--extractLastTaxId :: Maybe Taxon -> Maybe Int-extractLastTaxId taxon-  | isNothing taxon = Nothing-  | V.null lineageExVector = Nothing-  | otherwise = Just (lineageTaxId (V.head lineageExVector))-    where lineageExVector = V.fromList (lineageEx (fromJust taxon))--modelConstructionResult :: StaticOptions -> ModelConstruction -> IO ModelConstruction-modelConstructionResult staticOptions modelConstruction = do-  let currentIterationNumber = iterationNumber modelConstruction-  let outputDirectory = tempDirPath staticOptions-  logMessage ("Global search iteration: " ++ show currentIterationNumber ++ "\n") outputDirectory-  iterationSummary modelConstruction staticOptions-  let foundSequenceNumber = length (concatMap sequenceRecords (taxRecords modelConstruction))-  --extract queries-  --let querySeqIds = selectedQueries modelConstruction ----  let queries = extractQueries foundSequenceNumber modelConstruction ----  --let alignedSequences' = map nucleotideSequence (concatMap sequenceRecords (taxRecords modelConstruction)) ----  logVerboseMessage (verbositySwitch staticOptions) ("Queries:" ++ show queries ++ "\n") outputDirectory-  let iterationDirectory = outputDirectory ++ show currentIterationNumber ++ "/"-  createDirectory iterationDirectory-  let logFileDirectoryPath = iterationDirectory ++ "log"-  createDirectoryIfMissing False logFileDirectoryPath-  let expectThreshold = setBlastExpectThreshold modelConstruction-  (alignmentResults,currentPotentialMembers) <- if isJust (taxRestriction staticOptions)-    then do-      --taxonomic restriction-      let (upperTaxLimit,lowerTaxLimit) = setRestrictedTaxonomyLimits (fromJust (taxRestriction staticOptions))-      restrictedCandidates <- catchAll (searchCandidates staticOptions (taxRestriction staticOptions) currentIterationNumber upperTaxLimit lowerTaxLimit expectThreshold queries)-                     (\e -> do logWarning ("Warning: Search results iteration" ++ show currentIterationNumber ++ " - exception: " ++ show e) outputDirectory-                               return (SearchResult [] Nothing))-      let uniqueCandidates = filterDuplicates modelConstruction restrictedCandidates-      (restrictedAlignmentResults,restrictedPotentialMembers) <- catchAll (alignCandidates staticOptions modelConstruction (fromJust (taxRestriction staticOptions)) uniqueCandidates)-                           (\e -> do logWarning ("Warning: Alignment results iteration" ++ show currentIterationNumber ++ " - exception: " ++ show e) outputDirectory-                                     return  ([],[]))-      let currentPotentialMembers = [SearchResult restrictedPotentialMembers (blastDatabaseSize restrictedCandidates)]-      return (restrictedAlignmentResults,currentPotentialMembers)-    else do-      --taxonomic context archea-      let (upperTaxLimit1,lowerTaxLimit1) = (Just (2157 :: Int), Nothing)-      candidates1 <- catchAll  (searchCandidates staticOptions (Just "archea") currentIterationNumber upperTaxLimit1 lowerTaxLimit1 expectThreshold queries)-                     (\e -> do logWarning ("Warning: Search results iteration" ++ show currentIterationNumber ++ " - exception: " ++ show e) outputDirectory-                               return (SearchResult [] Nothing))-      let uniqueCandidates1 = filterDuplicates modelConstruction candidates1-      (alignmentResults1,potentialMembers1) <- catchAll (alignCandidates staticOptions modelConstruction "archea" uniqueCandidates1)-                           (\e -> do logWarning ("Warning: Alignment results iteration" ++ show currentIterationNumber ++ " - exception: " ++ show e) outputDirectory-                                     return  ([],[]))-      --taxonomic context bacteria-      let (upperTaxLimit2,lowerTaxLimit2) = (Just (2 :: Int), Nothing)-      candidates2 <- catchAll (searchCandidates staticOptions (Just "bacteria") currentIterationNumber upperTaxLimit2 lowerTaxLimit2 expectThreshold queries)-                     (\e -> do logWarning ("Warning: Search results iteration" ++ show currentIterationNumber ++ " - exception: " ++ show e) outputDirectory-                               return (SearchResult [] Nothing))-      let uniqueCandidates2 = filterDuplicates modelConstruction candidates2-      (alignmentResults2,potentialMembers2) <- catchAll (alignCandidates staticOptions modelConstruction "bacteria" uniqueCandidates2)-                           (\e -> do logWarning ("Warning: Alignment results iteration" ++ show currentIterationNumber ++ " - exception: " ++ show e) outputDirectory-                                     return  ([],[]))-      --taxonomic context eukaryia-      let (upperTaxLimit3,lowerTaxLimit3) = (Just (2759 :: Int), Nothing)-      candidates3 <- catchAll (searchCandidates staticOptions (Just "eukaryia") currentIterationNumber upperTaxLimit3 lowerTaxLimit3 expectThreshold queries)-                     (\e -> do logWarning ("Warning: Search results iteration" ++ show currentIterationNumber ++ " - exception: " ++ show e) outputDirectory-                               return (SearchResult [] Nothing))-      let uniqueCandidates3 = filterDuplicates modelConstruction candidates3-      (alignmentResults3,potentialMembers3) <- catchAll (alignCandidates staticOptions modelConstruction "eukaryia" uniqueCandidates3)-                           (\e -> do logWarning ("Warning: Alignment results iteration" ++ show currentIterationNumber ++ " - exception: " ++ show e) outputDirectory-                                     return  ([],[]))-      let alignmentResults = alignmentResults1 ++ alignmentResults2 ++ alignmentResults3-      let currentPotentialMembers = [SearchResult potentialMembers1 (blastDatabaseSize candidates1), SearchResult potentialMembers2 (blastDatabaseSize candidates2), SearchResult potentialMembers3 (blastDatabaseSize candidates3)]-      return (alignmentResults,currentPotentialMembers)-  let preliminaryFastaPath = iterationDirectory ++ "model.fa"-  let preliminaryCMPath = iterationDirectory ++ "model.cm"-  let preliminaryAlignmentPath = iterationDirectory ++ "model.stockholm"-  let preliminaryCMLogPath = iterationDirectory ++ "model.cm.log"-  let nextModelConstructionInput = constructNext currentIterationNumber modelConstruction alignmentResults Nothing Nothing [] currentPotentialMembers (alignmentModeInfernal modelConstruction)-  if (null alignmentResults) && not (alignmentModeInfernal modelConstruction)-    then do-      logVerboseMessage (verbositySwitch staticOptions) "Alignment result initial mode\n" outputDirectory-      logMessage "Message: No sequences found that statisfy filters. Try to reconstruct model with less strict cutoff parameters." outputDirectory-      let alignedSequences = extractAlignedSequences (iterationNumber modelConstruction) modelConstruction-      let alignmentSequences = map snd (V.toList (V.concat [alignedSequences]))-      writeFasta preliminaryFastaPath alignmentSequences-      let cmBuildFilepath = iterationDirectory ++ "model" ++ ".cmbuild"-      let refinedAlignmentFilepath = iterationDirectory ++ "modelrefined" ++ ".stockholm"-      let cmBuildOptions ="--refine " ++ refinedAlignmentFilepath-      let foldFilepath = iterationDirectory ++ "model" ++ ".fold"-      _ <- systemRNAfold preliminaryFastaPath foldFilepath-      foldoutput <- readRNAfold foldFilepath-      let seqStructure = foldSecondaryStructure (fromRight foldoutput)-      let stockholAlignment = convertFastaFoldStockholm (head alignmentSequences) seqStructure-      writeFile preliminaryAlignmentPath stockholAlignment-      _ <- systemCMbuild cmBuildOptions preliminaryAlignmentPath preliminaryCMPath cmBuildFilepath-      _ <- systemCMcalibrate "fast" (cpuThreads staticOptions) preliminaryCMPath preliminaryCMLogPath-      reevaluatePotentialMembers staticOptions nextModelConstructionInput-    else-      if (alignmentModeInfernal modelConstruction)-        then do-          logVerboseMessage (verbositySwitch staticOptions) ("Alignment construction with candidates - infernal mode\n") outputDirectory-          constructModel nextModelConstructionInput staticOptions-          writeFile (iterationDirectory ++ "done") ""-          logMessage (iterationSummaryLog nextModelConstructionInput) outputDirectory-          logVerboseMessage (verbositySwitch staticOptions) (show nextModelConstructionInput) outputDirectory-          resultModelConstruction <- reevaluatePotentialMembers staticOptions nextModelConstructionInput-          return resultModelConstruction-        else do-          logVerboseMessage (verbositySwitch staticOptions) ("Alignment construction with candidates - initial mode\n") outputDirectory-          constructModel nextModelConstructionInput staticOptions-          let nextModelConstructionInputInfernalMode = nextModelConstructionInput {alignmentModeInfernal = True}-          logMessage (iterationSummaryLog nextModelConstructionInputInfernalMode) outputDirectory-          logVerboseMessage (verbositySwitch staticOptions) (show nextModelConstructionInputInfernalMode) outputDirectory-          writeFile (iterationDirectory ++ "done") ""-          resultModelConstruction <- reevaluatePotentialMembers staticOptions nextModelConstructionInputInfernalMode-          return resultModelConstruction---- | Reevaluate collected potential members for inclusion in the result model-reevaluatePotentialMembers :: StaticOptions -> ModelConstruction -> IO ModelConstruction-reevaluatePotentialMembers staticOptions modelConstruction = do-  let currentIterationNumber = iterationNumber modelConstruction-  let outputDirectory = tempDirPath staticOptions-  iterationSummary modelConstruction staticOptions-  logMessage ("Reevaluation of potential members iteration: " ++ show currentIterationNumber ++ "\n") outputDirectory-  let iterationDirectory = outputDirectory ++ show currentIterationNumber ++ "/"-  createDirectory iterationDirectory-  let indexedPotentialMembers = V.indexed (V.fromList (potentialMembers modelConstruction))-  potentialMembersAlignmentResultVector <- V.mapM (\(i,searchresult) -> (alignCandidates staticOptions modelConstruction (show i ++ "_") searchresult)) indexedPotentialMembers-  let potentialMembersAlignmentResults = V.toList potentialMembersAlignmentResultVector-  let alignmentResults = concatMap fst potentialMembersAlignmentResults-  let discardedMembers = concatMap snd potentialMembersAlignmentResults-  writeFile (outputDirectory  ++ "log/discarded") (concatMap show discardedMembers)-  let resultFastaPath = outputDirectory  ++ "result.fa"-  let resultCMPath = outputDirectory ++ "result.cm"-  let resultAlignmentPath = outputDirectory ++ "result.stockholm"-  let resultClustalFilepath = outputDirectory ++ "result.clustal"-  let resultCMLogPath = outputDirectory ++ "log/result.cm.log"-  if null alignmentResults-    then do-      let lastIterationFastaPath = outputDirectory ++ show (currentIterationNumber - 1)++ "/model.fa"-      let lastIterationAlignmentPath = outputDirectory ++ show (currentIterationNumber - 1)  ++ "/model.stockholm"-      let lastIterationCMPath = outputDirectory ++ show (currentIterationNumber - 1)++ "/model.cm"-      copyFile lastIterationCMPath resultCMPath-      --copyFile lastIterationCMPath (resultCMPath ++ ".bak1")-      copyFile lastIterationFastaPath resultFastaPath-      copyFile lastIterationAlignmentPath resultAlignmentPath-      _ <- systemCMcalibrate "standard" (cpuThreads staticOptions) resultCMPath resultCMLogPath-      systemCMalign ("--outformat=Clustal --cpu " ++ show (cpuThreads staticOptions)) resultCMPath resultFastaPath resultClustalFilepath-      writeFile (iterationDirectory ++ "done") ""-      return modelConstruction-    else do-      let lastIterationFastaPath = outputDirectory ++ show currentIterationNumber ++ "/model.fa"-      let lastIterationAlignmentPath = outputDirectory ++ show currentIterationNumber  ++ "/model.stockholm"-      let lastIterationCMPath = outputDirectory ++ show currentIterationNumber ++ "/model.cm"-      logVerboseMessage (verbositySwitch staticOptions) "Alignment construction with candidates - infernal mode\n" outputDirectory-      let nextModelConstructionInput = constructNext currentIterationNumber modelConstruction alignmentResults Nothing Nothing [] [] (alignmentModeInfernal modelConstruction)-      constructModel nextModelConstructionInput staticOptions-      copyFile lastIterationCMPath resultCMPath-      --debug-      --copyFile lastIterationCMPath (resultCMPath ++ ".bak2")-      copyFile lastIterationFastaPath resultFastaPath-      copyFile lastIterationAlignmentPath resultAlignmentPath-      logMessage (iterationSummaryLog nextModelConstructionInput) outputDirectory-      logVerboseMessage (verbositySwitch staticOptions) (show nextModelConstructionInput) outputDirectory-      _ <- systemCMcalibrate "standard" (cpuThreads staticOptions) resultCMPath resultCMLogPath-      systemCMalign ("--outformat=Clustal --cpu " ++ show (cpuThreads staticOptions)) resultCMPath resultFastaPath resultClustalFilepath-      writeFile (iterationDirectory ++ "done") ""-      return nextModelConstructionInput-------------------------------------------------------------alignmentConstructionWithCandidates :: Maybe Taxon -> Maybe Int -> SearchResult -> StaticOptions -> ModelConstruction -> IO ModelConstruction-alignmentConstructionWithCandidates currentTaxonomicContext currentUpperTaxonomyLimit searchResults staticOptions modelConstruction = do-    --candidates usedUpperTaxonomyLimit blastDatabaseSize -    let currentIterationNumber = iterationNumber modelConstruction-    let iterationDirectory = tempDirPath staticOptions ++ show currentIterationNumber ++ "/"-    --let usedUpperTaxonomyLimit = (snd (head candidates))                               -    --align search result-    (alignmentResults,potentialMemberEntries) <- catchAll (alignCandidates staticOptions modelConstruction "" searchResults)-                        (\e -> do logWarning ("Warning: Alignment results iteration" ++ show (iterationNumber modelConstruction) ++ " - exception: " ++ show e) (tempDirPath staticOptions)-                                  return ([],[]))-    let currentPotentialMembers = [SearchResult potentialMemberEntries (blastDatabaseSize searchResults)]-    if (null alignmentResults) && not (alignmentModeInfernal modelConstruction)-      then do-        logVerboseMessage (verbositySwitch staticOptions) ("Alignment construction with candidates - length 1 - inital mode" ++ "\n") (tempDirPath staticOptions)-        --too few sequences for alignment. because of lack in sequences no cm was constructed before-        --reusing previous modelconstruction with increased upperTaxonomyLimit but include found sequence-        --prepare next iteration-        let newTaxEntries = taxRecords modelConstruction ++ buildTaxRecords alignmentResults currentIterationNumber-        let nextModelConstructionInputWithThreshold = modelConstruction {iterationNumber = currentIterationNumber + 1,upperTaxonomyLimit = currentUpperTaxonomyLimit, taxRecords = newTaxEntries,taxonomicContext = currentTaxonomicContext}-        logMessage (iterationSummaryLog nextModelConstructionInputWithThreshold) (tempDirPath staticOptions)-        logVerboseMessage (verbositySwitch staticOptions)  (show nextModelConstructionInputWithThreshold) (tempDirPath staticOptions)     ----      -        writeFile (iterationDirectory ++ "done") ""-        modelConstructer staticOptions nextModelConstructionInputWithThreshold-      else-        if (alignmentModeInfernal modelConstruction)-          then do-            logVerboseMessage (verbositySwitch staticOptions) ("Alignment construction with candidates - infernal mode\n") (tempDirPath staticOptions)-            --prepare next iteration-            let nextModelConstructionInput = constructNext currentIterationNumber modelConstruction alignmentResults currentUpperTaxonomyLimit currentTaxonomicContext [] currentPotentialMembers True-            constructModel nextModelConstructionInput staticOptions-            writeFile (iterationDirectory ++ "done") ""-            logMessage (iterationSummaryLog nextModelConstructionInput) (tempDirPath staticOptions)-            logVerboseMessage (verbositySwitch staticOptions)  (show nextModelConstructionInput) (tempDirPath staticOptions)-            --select queries-            currentSelectedQueries <- selectQueries staticOptions modelConstruction alignmentResults-            let nextModelConstructionInputWithQueries = nextModelConstructionInput {selectedQueries = currentSelectedQueries}-            nextModelConstruction <- modelConstructer staticOptions nextModelConstructionInputWithQueries-            return nextModelConstruction-          else do-            logVerboseMessage (verbositySwitch staticOptions) ("Alignment construction with candidates - initial mode\n") (tempDirPath staticOptions)-            --First round enough candidates are available for modelconstruction, alignmentModeInfernal is set to true after this iteration-            --prepare next iteration-            let nextModelConstructionInput = constructNext currentIterationNumber modelConstruction alignmentResults currentUpperTaxonomyLimit currentTaxonomicContext [] currentPotentialMembers False-            constructModel nextModelConstructionInput staticOptions-            currentSelectedQueries <- selectQueries staticOptions modelConstruction alignmentResults-            --select queries-            let nextModelConstructionInputWithInfernalMode = nextModelConstructionInput {alignmentModeInfernal = True, selectedQueries = currentSelectedQueries}-            logMessage (iterationSummaryLog  nextModelConstructionInputWithInfernalMode) (tempDirPath staticOptions)-            logVerboseMessage (verbositySwitch staticOptions)  (show  nextModelConstructionInputWithInfernalMode) (tempDirPath staticOptions)-            writeFile (iterationDirectory ++ "done") ""-            nextModelConstruction <- modelConstructer staticOptions nextModelConstructionInputWithInfernalMode-            return nextModelConstruction--alignmentConstructionWithoutCandidates :: Maybe Taxon -> Maybe Int ->  StaticOptions -> ModelConstruction -> IO ModelConstruction-alignmentConstructionWithoutCandidates currentTaxonomicContext upperTaxLimit staticOptions modelConstruction = do-    let currentIterationNumber = iterationNumber modelConstruction-    let iterationDirectory = tempDirPath staticOptions ++ show currentIterationNumber ++ "/"-    --Found no new candidates in this iteration, reusing previous modelconstruction with increased upperTaxonomyLimit-    let nextModelConstructionInputWithThreshold = modelConstruction  {iterationNumber = currentIterationNumber + 1,upperTaxonomyLimit = upperTaxLimit,taxonomicContext = currentTaxonomicContext}-    --copy model and alignment from last iteration in place if present-    let previousIterationCMPath = tempDirPath staticOptions ++ show (currentIterationNumber - 1) ++ "/model.cm"-    previousIterationCMexists <- doesFileExist previousIterationCMPath-    if previousIterationCMexists-      then do-        logVerboseMessage (verbositySwitch staticOptions) "Alignment construction no candidates - previous cm\n" (tempDirPath staticOptions)-        let previousIterationFastaPath = tempDirPath staticOptions ++ show (currentIterationNumber - 1) ++ "/model.fa"-        let previousIterationAlignmentPath = tempDirPath staticOptions ++ show (currentIterationNumber - 1) ++ "/model.stockholm"-        let thisIterationFastaPath = tempDirPath staticOptions ++ show (currentIterationNumber) ++ "/model.fa"-        let thisIterationAlignmentPath = tempDirPath staticOptions ++ show (currentIterationNumber) ++ "/model.stockholm"-        let thisIterationCMPath = tempDirPath staticOptions ++ show (currentIterationNumber) ++ "/model.cm"-        copyFile previousIterationFastaPath thisIterationFastaPath-        copyFile previousIterationAlignmentPath thisIterationAlignmentPath-        copyFile previousIterationCMPath thisIterationCMPath-        logMessage (iterationSummaryLog nextModelConstructionInputWithThreshold) (tempDirPath staticOptions)-        logVerboseMessage (verbositySwitch staticOptions) (show nextModelConstructionInputWithThreshold) (tempDirPath staticOptions)-        writeFile (iterationDirectory ++ "done") ""-        modelConstructer staticOptions nextModelConstructionInputWithThreshold-      else do-        logVerboseMessage (verbositySwitch staticOptions) "Alignment construction no candidates - no previous iteration cm\n" (tempDirPath staticOptions)-        logMessage (iterationSummaryLog nextModelConstructionInputWithThreshold) (tempDirPath staticOptions)-        logVerboseMessage (verbositySwitch staticOptions) (show nextModelConstructionInputWithThreshold) (tempDirPath staticOptions)    ----       -        writeFile (iterationDirectory ++ "done") ""-        modelConstructer staticOptions nextModelConstructionInputWithThreshold--findTaxonomyStart :: Maybe String -> String -> Sequence -> IO Int-findTaxonomyStart inputBlastDatabase temporaryDirectory querySequence = do-  let queryIndexString = "1"-  let hitNumberQuery = buildHitNumberQuery "&HITLIST_SIZE=10"-  let registrationInfo = buildRegistration "RNAlien" "florian.eggenhofer@univie.ac.at"-  let blastQuery = BlastHTTPQuery (Just "ncbi") (Just "blastn") inputBlastDatabase [querySequence] (Just (hitNumberQuery ++ registrationInfo)) (Just (5400000000 :: Int))-  logMessage "No tax id provided - Sending find taxonomy start blast query \n" temporaryDirectory-  blastOutput <- CE.catch (blastHTTP blastQuery)-                       (\e -> do let err = show (e :: CE.IOException)-                                 logWarning ("Warning: Blast attempt failed:" ++ " " ++ err) temporaryDirectory-                                 error "findTaxonomyStart: Blast attempt failed"-                                 return (Left ""))-  let logFileDirectoryPath =  temporaryDirectory ++ "taxonomystart" ++ "/"-  createDirectory logFileDirectoryPath-  writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString  ++ "_1blastOutput") (show blastOutput)-  logEither blastOutput temporaryDirectory-  let blastHitsArePresent = either (const False) blastMatchesPresent blastOutput-  if blastHitsArePresent-     then do-       let rightBlast = fromRight blastOutput-       let bestHit = getBestHit rightBlast-       bestBlastHitTaxIdOutput <- retrieveBlastHitTaxIdEntrez [bestHit]-       let taxIdFromEntrySummaries = extractTaxIdFromEntrySummaries (snd bestBlastHitTaxIdOutput)-       Control.Monad.when (null taxIdFromEntrySummaries) (error "findTaxonomyStart: - head: empty list of taxonomy entry summary for best hit")-       let rightBestTaxIdResult = head taxIdFromEntrySummaries-       logMessage ("Initial TaxId: " ++ show rightBestTaxIdResult ++ "\n") temporaryDirectory-       CE.evaluate rightBestTaxIdResult-     else error "Find taxonomy start: Could not find blast hits to use as a taxonomic starting point"--searchCandidates :: StaticOptions -> Maybe String -> Int ->  Maybe Int -> Maybe Int -> Double -> [Sequence] -> IO SearchResult-searchCandidates staticOptions finaliterationprefix iterationnumber upperTaxLimit lowerTaxLimit expectThreshold inputQuerySequences = do-  --let fastaSeqData = seqdata _querySequence-  Control.Monad.when (null inputQuerySequences) $ error "searchCandidates: - head: empty list of query sequences"-  let queryLength = fromIntegral (seqlength (head inputQuerySequences))-  let queryIndexString = "1"-  let entrezTaxFilter = buildTaxFilterQuery upperTaxLimit lowerTaxLimit-  logVerboseMessage (verbositySwitch staticOptions) ("entrezTaxFilter" ++ show entrezTaxFilter ++ "\n") (tempDirPath staticOptions)-  let hitNumberQuery = buildHitNumberQuery "&HITLIST_SIZE=5000&EXPECT=" ++ show expectThreshold-  let registrationInfo = buildRegistration "RNAlien" "florian.eggenhofer@univie.ac.at"-  let softmaskFilter = if blastSoftmaskingToggle staticOptions then "&FILTER=True&FILTER=m" else ""-  let blastQuery = BlastHTTPQuery (Just "ncbi") (Just "blastn") (blastDatabase staticOptions) inputQuerySequences  (Just (hitNumberQuery ++ entrezTaxFilter ++ softmaskFilter ++ registrationInfo)) (Just (5400000000 :: Int))-  --appendFile "/scratch/egg/blasttest/queries" ("\nBlast query:\n"  ++ show blastQuery ++ "\n") -  logVerboseMessage (verbositySwitch staticOptions) ("Sending blast query " ++ show iterationnumber ++ "\n") (tempDirPath staticOptions)-  blastOutput <- CE.catch (blastHTTP blastQuery)-                       (\e -> do let err = show (e :: CE.IOException)-                                 logWarning ("Warning: Blast attempt failed:" ++ " " ++ err) (tempDirPath staticOptions)-                                 return (Left ""))-  let logFileDirectoryPath = tempDirPath staticOptions ++ show iterationnumber ++ "/" ++ fromMaybe "" finaliterationprefix ++ "log"-  logDirectoryPresent <- doesDirectoryExist logFileDirectoryPath-  Control.Monad.when (not logDirectoryPresent) $ createDirectory (logFileDirectoryPath)-  writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString  ++ "_1blastOutput") (show blastOutput)-  logEither blastOutput (tempDirPath staticOptions)-  let blastHitsArePresent = either (const False) blastMatchesPresent blastOutput-  if blastHitsArePresent-     then do-       let rightBlast = fromRight blastOutput-       -- bestBlastHitTaxIdOutput <- retrieveBlastHitTaxIdEntrez [bestHit]-       -- let taxIdFromEntrySummaries = extractTaxIdFromEntrySummaries bestBlastHitTaxIdOutput-       -- if (null taxIdFromEntrySummaries) then (error "searchCandidates: - head: empty list of taxonomy entry summary for best hit")  else return ()-       -- let rightBestTaxIdResult = head taxIdFromEntrySummaries-       -- logVerboseMessage (verbositySwitch staticOptions) ("rightbestTaxIdResult: " ++ (show rightBestTaxIdResult) ++ "\n") (tempDirPath staticOptions)-       let blastHits = concatMap hits (results rightBlast)-       writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString  ++ "_2blastHits") (showlines blastHits)-       --filter by length-       let blastHitsFilteredByLength = filterByHitLength blastHits queryLength (lengthFilterToggle staticOptions)-       writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString  ++ "_3blastHitsFilteredByLength") (showlines blastHitsFilteredByLength)-       let blastHitsFilteredByCoverage = filterByCoverage blastHitsFilteredByLength queryLength (coverageFilterToggle staticOptions)-       writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString  ++ "_3ablastHitsFilteredByLength") (showlines blastHitsFilteredByCoverage)-       --tag BlastHits with TaxId-       blastHitsWithTaxIdOutput <- retrieveBlastHitsTaxIdEntrez blastHitsFilteredByCoverage-       let uncheckedBlastHitsWithTaxIdList = map (Control.Arrow.second extractTaxIdFromEntrySummaries) blastHitsWithTaxIdOutput-       let checkedBlastHitsWithTaxId = filter (\(_,taxids) -> not (null taxids)) uncheckedBlastHitsWithTaxIdList-       --todo checked blasthittaxidswithblasthits need to be merged as taxid blasthit pairs-       let blastHitsWithTaxId = zip (concatMap fst checkedBlastHitsWithTaxId) (concatMap snd checkedBlastHitsWithTaxId)-       blastHitsWithParentTaxIdOutput <- retrieveParentTaxIdsEntrez blastHitsWithTaxId-       --let blastHitsWithParentTaxId = concat blastHitsWithParentTaxIdOutput-       -- filter by ParentTaxId (only one hit per TaxId)-       let blastHitsFilteredByParentTaxIdWithParentTaxId = filterByParentTaxId blastHitsWithParentTaxIdOutput True-       --let blastHitsFilteredByParentTaxId = map fst blastHitsFilteredByParentTaxIdWithParentTaxId-       writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString ++ "_4blastHitsFilteredByParentTaxId") (showlines blastHitsFilteredByParentTaxIdWithParentTaxId)-       -- Filtering with TaxTree (only hits from the same subtree as besthit)-       --let blastHitsWithTaxId = zip blastHitsFilteredByParentTaxId blastHittaxIdList-       --let (_, filteredBlastResults) = filterByNeighborhoodTreeConditional alignndmentModeInfernalToggle upperTaxLimit blastHitsWithTaxId (inputTaxNodes staticOptions) (fromJust upperTaxLimit) (singleHitperTaxToggle staticOptions)-       --writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString ++ "_5filteredBlastResults") (showlines filteredBlastResults)-       -- Coordinate generation-       let nonEmptyfilteredBlastResults = filter (\(blasthit,_) -> not (null (matches blasthit))) blastHitsFilteredByParentTaxIdWithParentTaxId-       let requestedSequenceElements = map (getRequestedSequenceElement queryLength) nonEmptyfilteredBlastResults-       writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString ++  "_6requestedSequenceElements") (showlines requestedSequenceElements)-       -- Retrieval of full sequences from entrez-       --fullSequencesWithSimilars <- retrieveFullSequences requestedSequenceElements-       fullSequencesWithSimilars <- retrieveFullSequences staticOptions requestedSequenceElements-       if null fullSequencesWithSimilars-         then do-           writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString ++ "_10afullSequencesWithSimilars") "No sequences retrieved"-           CE.evaluate (SearchResult [] Nothing)-         else do-           writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString ++ "_10afullSequencesWithSimilars") (showlines fullSequencesWithSimilars)-           let fullSequences = filterIdenticalSequences fullSequencesWithSimilars 100-           --let fullSequencesWithOrigin = map (\(parsedFasta,taxid,seqSubject) -> (parsedFasta,taxid,seqSubject,'B')) fullSequences-           writeFile (logFileDirectoryPath ++ "/" ++ queryIndexString ++ "_10fullSequences") (showlines fullSequences)-           let maybeFractionEvalueMatch = getHitWithFractionEvalue rightBlast-           if isNothing maybeFractionEvalueMatch-             then CE.evaluate (SearchResult [] Nothing)-             else do-               let fractionEvalueMatch = fromJust maybeFractionEvalueMatch-               let dbSize = computeDataBaseSize (e_val fractionEvalueMatch) (bits fractionEvalueMatch) (fromIntegral queryLength ::Double)-               CE.evaluate (SearchResult fullSequences (Just dbSize))-     else CE.evaluate (SearchResult [] Nothing)---- |Computes size of blast db in Mb -computeDataBaseSize :: Double -> Double -> Double -> Double-computeDataBaseSize evalue bitscore querylength = ((evalue * 2 ** bitscore) / querylength)/10^(6 :: Integer)--alignCandidates :: StaticOptions -> ModelConstruction -> String -> SearchResult -> IO ([(Sequence,Int,L.ByteString)],[(Sequence,Int,L.ByteString)])-alignCandidates staticOptions modelConstruction multipleSearchResultPrefix searchResults = do-  let iterationDirectory = tempDirPath staticOptions ++ show (iterationNumber modelConstruction) ++ "/" ++ multipleSearchResultPrefix-  createDirectoryIfMissing False (iterationDirectory ++ "log")-  if null (candidates searchResults)-    then do-      writeFile (iterationDirectory ++ "log" ++ "/11candidates") "No candidates to align"-      return ([],[])-    else do-      --refilter for similarity-      writeFile (iterationDirectory ++ "log" ++ "/11candidates") (showlines (candidates searchResults))-      let alignedSequences = map snd (V.toList (extractAlignedSequences (iterationNumber modelConstruction) modelConstruction))-      let filteredCandidates = filterWithCollectedSequences (candidates searchResults) alignedSequences 99-      writeFile (iterationDirectory ++ "log" ++ "/12candidatesFilteredByCollected") (showlines filteredCandidates)-      if alignmentModeInfernal modelConstruction-        then alignCandidatesInfernalMode staticOptions modelConstruction multipleSearchResultPrefix (blastDatabaseSize searchResults) filteredCandidates-        else alignCandidatesInitialMode staticOptions modelConstruction multipleSearchResultPrefix filteredCandidates--alignCandidatesInfernalMode :: StaticOptions -> ModelConstruction -> String -> Maybe Double -> [(Sequence,Int,L.ByteString)] -> IO ([(Sequence,Int,L.ByteString)],[(Sequence,Int,L.ByteString)])-alignCandidatesInfernalMode staticOptions modelConstruction multipleSearchResultPrefix blastDbSize filteredCandidates = do-  let iterationDirectory = tempDirPath staticOptions ++ show (iterationNumber modelConstruction) ++ "/" ++ multipleSearchResultPrefix-  let candidateSequences = extractCandidateSequences filteredCandidates-  logVerboseMessage (verbositySwitch staticOptions) "Alignment Mode Infernal\n" (tempDirPath staticOptions)-  let indexedCandidateSequenceList = V.toList candidateSequences-  let cmSearchFastaFilePaths = map (constructFastaFilePaths iterationDirectory) indexedCandidateSequenceList-  let cmSearchFilePaths = map (constructCMsearchFilePaths iterationDirectory) indexedCandidateSequenceList-  let covarianceModelPath = tempDirPath staticOptions ++ show (iterationNumber modelConstruction - 1) ++ "/" ++ "model.cm"-  mapM_ (\(number,_nucleotideSequence) -> writeFasta (iterationDirectory ++ show number ++ ".fa") [_nucleotideSequence]) indexedCandidateSequenceList-  let zippedFastaCMSearchResultPaths = zip cmSearchFastaFilePaths cmSearchFilePaths-  --check with cmSearch-  mapM_ (uncurry (systemCMsearch (cpuThreads staticOptions) ("-Z " ++ show (fromJust blastDbSize)) covarianceModelPath)) zippedFastaCMSearchResultPaths-  cmSearchResults <- mapM readCMSearch cmSearchFilePaths-  writeFile (iterationDirectory ++ "cm_error") (concatMap show (lefts cmSearchResults))-  let rightCMSearchResults = rights cmSearchResults-  let cmSearchCandidatesWithSequences = zip rightCMSearchResults filteredCandidates-  let (trimmedSelectedCandidates,potentialCandidates,rejectedCandidates) = evaluePartitionTrimCMsearchHits (evalueThreshold modelConstruction) cmSearchCandidatesWithSequences-  createDirectoryIfMissing False (iterationDirectory ++ "log")-  writeFile (iterationDirectory ++ "log" ++ "/13selectedCandidates'") (showlines trimmedSelectedCandidates)-  writeFile (iterationDirectory ++ "log" ++ "/14rejectedCandidates'") (showlines rejectedCandidates)-  writeFile (iterationDirectory ++ "log" ++ "/15potentialCandidates'") (showlines potentialCandidates)-  return (map snd trimmedSelectedCandidates,map snd potentialCandidates)--alignCandidatesInitialMode :: StaticOptions -> ModelConstruction -> String -> [(Sequence,Int,L.ByteString)] -> IO ([(Sequence,Int,L.ByteString)],[(Sequence,Int,L.ByteString)])-alignCandidatesInitialMode staticOptions modelConstruction multipleSearchResultPrefix filteredCandidates = do-  let iterationDirectory = tempDirPath staticOptions ++ show (iterationNumber modelConstruction) ++ "/" ++ multipleSearchResultPrefix-  --writeFile (iterationDirectory ++ "log" ++ "/11bcandidates") (showlines filteredCandidates)-  createDirectoryIfMissing False (iterationDirectory ++ "log")-  let candidateSequences = extractCandidateSequences filteredCandidates-  --writeFile (iterationDirectory ++ "log" ++ "/11ccandidates") (showlines (V.toList candidateSequences))-  logVerboseMessage (verbositySwitch staticOptions) "Alignment Mode Initial\n" (tempDirPath staticOptions)-  --write Fasta sequences-  let inputFastaFilepath = iterationDirectory ++ "input.fa"-  let inputFoldFilepath = iterationDirectory ++ "input.fold"-  writeFasta (iterationDirectory ++ "input.fa") [inputFasta modelConstruction]-  logMessage (showlines (V.toList candidateSequences)) (tempDirPath staticOptions)-  V.mapM_ (\(number,nucleotideSequence') -> writeFasta (iterationDirectory ++ show number ++ ".fa") [nucleotideSequence']) candidateSequences-  let candidateFastaFilepath = V.toList (V.map (\(number,_) -> iterationDirectory ++ show number ++ ".fa") candidateSequences)-  let candidateFoldFilepath = V.toList (V.map (\(number,_) -> iterationDirectory ++ show number ++ ".fold") candidateSequences)-  let locarnainClustalw2FormatFilepath =  V.toList (V.map (\(number,_) -> iterationDirectory ++ show number ++ "." ++ "clustalmlocarna") candidateSequences)-  let candidateAliFoldFilepath = V.toList (V.map (\(number,_) -> iterationDirectory ++ show number ++ ".alifold") candidateSequences)-  let locarnaFilepath = V.toList (V.map (\(number,_) -> iterationDirectory ++ show number ++ "." ++ "mlocarna") candidateSequences)-  alignSequences "locarna" " --write-structure --free-endgaps=++-- " (replicate (V.length candidateSequences) inputFastaFilepath) candidateFastaFilepath locarnainClustalw2FormatFilepath locarnaFilepath-  --compute SequenceIdentities-  let sequenceIdentities = V.map (\(_,s) -> sequenceIdentity (inputFasta modelConstruction) s/(100 :: Double)) candidateSequences-  --compute SCI-  systemRNAfold inputFastaFilepath inputFoldFilepath-  inputfoldResult <- readRNAfold inputFoldFilepath-  let inputFoldMFE = foldingEnergy (fromRight inputfoldResult)-  mapM_ (uncurry systemRNAfold) (zip candidateFastaFilepath candidateFoldFilepath)-  foldResults <- mapM readRNAfold candidateFoldFilepath-  let candidateMFEs = map (foldingEnergy . fromRight) foldResults-  let averageMFEs = map (\candidateMFE -> (candidateMFE + inputFoldMFE)/2) candidateMFEs-  mapM_ (uncurry (systemRNAalifold "")) (zip locarnainClustalw2FormatFilepath candidateAliFoldFilepath)-  alifoldResults <- mapM readRNAalifold candidateAliFoldFilepath-  let consensusMFE = map (alignmentConsensusMinimumFreeEnergy . fromRight) alifoldResults-  let sciidfraction = map (\(consMFE,averMFE,seqId) -> (consMFE/averMFE)/seqId) (zip3 consensusMFE averageMFEs (V.toList sequenceIdentities))-  let idlog = concatMap (\(sciidfraction',consMFE,averMFE,seqId) -> show sciidfraction' ++ "," ++ show consMFE ++ "," ++ show averMFE ++ "," ++ show seqId ++ "\n")(zip4 sciidfraction consensusMFE averageMFEs (V.toList sequenceIdentities))-  writeFile (iterationDirectory ++ "log" ++ "/idlog") idlog-  let alignedCandidates = zip sciidfraction filteredCandidates-  writeFile (iterationDirectory ++ "log" ++ "/zscores") (showlines alignedCandidates)-  let (selectedCandidates,rejectedCandidates) = partition (\(sciidfraction',_) -> sciidfraction' > nSCICutoff staticOptions) alignedCandidates-  mapM_ print (zip3 consensusMFE averageMFEs (V.toList sequenceIdentities))-  writeFile (iterationDirectory ++ "log" ++ "/13selectedCandidates") (showlines selectedCandidates)-  writeFile (iterationDirectory ++ "log" ++ "/14rejectedCandidates") (showlines rejectedCandidates)-  return (map snd selectedCandidates,[])--setClusterNumber :: Int -> Int-setClusterNumber x-  | x <= 5 = x-  | otherwise = 5--findCutoffforClusterNumber :: Dendrogram a -> Int -> Distance -> Distance-findCutoffforClusterNumber clustaloDendrogram numberOfClusters currentCutoff-  | currentClusterNumber >= numberOfClusters = currentCutoff-  | otherwise = findCutoffforClusterNumber clustaloDendrogram numberOfClusters (currentCutoff-0.01)-    where currentClusterNumber = length (cutAt clustaloDendrogram currentCutoff)---- Selects Query sequence ids from all collected seqeuences. Queries are then fetched by extractQueries function.-selectQueries :: StaticOptions -> ModelConstruction -> [(Sequence,Int,L.ByteString)] -> IO [Sequence]-selectQueries staticOptions modelConstruction selectedCandidates = do-  logVerboseMessage (verbositySwitch staticOptions) "SelectQueries\n" (tempDirPath staticOptions)-  --Extract sequences from modelconstruction-  let alignedSequences = extractAlignedSequences (iterationNumber modelConstruction) modelConstruction-  let candidateSequences = extractQueryCandidates selectedCandidates-  let iterationDirectory = tempDirPath staticOptions ++ show (iterationNumber modelConstruction) ++ "/"-  let stockholmFilepath = iterationDirectory ++ "model" ++ ".stockholm"-  let alignmentSequences = map snd (V.toList (V.concat [candidateSequences,alignedSequences]))-  if length alignmentSequences > 3-    then-      if (querySelectionMethod staticOptions) == "clustering"-        then do-          --write Fasta sequences-          writeFasta (iterationDirectory ++ "query" ++ ".fa") alignmentSequences-          let fastaFilepath = iterationDirectory ++ "query" ++ ".fa"-          let clustaloFilepath = iterationDirectory ++ "query" ++ ".clustalo"-          let clustaloDistMatrixPath = iterationDirectory ++ "query" ++ ".matrix"-          alignSequences "clustalo" ("--full --distmat-out=" ++ clustaloDistMatrixPath ++ " ") [fastaFilepath] [] [clustaloFilepath] []-          idsDistancematrix <- readClustaloDistMatrix clustaloDistMatrixPath-          logEither idsDistancematrix (tempDirPath staticOptions)-          let (clustaloIds,clustaloDistMatrix) = fromRight idsDistancematrix-          logVerboseMessage (verbositySwitch staticOptions) ("Clustalid: " ++ intercalate "," clustaloIds ++ "\n") (tempDirPath staticOptions)-          logVerboseMessage (verbositySwitch staticOptions) ("Distmatrix: " ++ show clustaloDistMatrix ++ "\n") (tempDirPath staticOptions)-          let clustaloDendrogram = dendrogram UPGMA clustaloIds (getDistanceMatrixElements clustaloIds clustaloDistMatrix)-          logVerboseMessage (verbositySwitch staticOptions) ("ClustaloDendrogram: " ++ show  clustaloDendrogram ++ "\n") (tempDirPath staticOptions)-          logVerboseMessage (verbositySwitch staticOptions) ("ClustaloDendrogram: " ++ show clustaloDistMatrix ++ "\n") (tempDirPath staticOptions)-          let numberOfClusters = setClusterNumber (length alignmentSequences)-          logVerboseMessage (verbositySwitch staticOptions) ("numberOfClusters: " ++ show numberOfClusters ++ "\n") (tempDirPath staticOptions)-          let dendrogramStartCutDistance = 1 :: Double-          let dendrogramCutDistance' = findCutoffforClusterNumber clustaloDendrogram numberOfClusters dendrogramStartCutDistance-          logVerboseMessage (verbositySwitch staticOptions) ("dendrogramCutDistance': " ++ show dendrogramCutDistance' ++ "\n") (tempDirPath staticOptions)-          let cutDendrogram = cutAt clustaloDendrogram dendrogramCutDistance'-          --putStrLn "cutDendrogram: "-          --print cutDendrogram-          let currentSelectedSequenceIds = map L.pack (take (queryNumber staticOptions) (concatMap (take 1 . elements) cutDendrogram))-          --let alignedSequences = fastaSeqData:map nucleotideSequence (concatMap sequenceRecords (taxRecords modelconstruction))-          let fastaSelectedSequences = concatMap (filterSequenceById alignmentSequences) currentSelectedSequenceIds-          stockholmSelectedSequences <- extractAlignmentSequencesByIds stockholmFilepath currentSelectedSequenceIds-          --Stockholm sequnces contain conservation annotation from cmalign in infernal mode-          let currentSelectedSequences = if (blastSoftmaskingToggle staticOptions) then stockholmSelectedSequences else fastaSelectedSequences-          --let currentSelectedQueries = concatMap (\querySeqId -> filter (\alignedSeq -> L.unpack (unSL (seqid alignedSeq)) == querySeqId) alignmentSequences) querySeqIds-          logVerboseMessage (verbositySwitch staticOptions) ("SelectedQueries: " ++ show currentSelectedSequences ++ "\n") (tempDirPath staticOptions)-          writeFile (tempDirPath staticOptions ++ show (iterationNumber modelConstruction) ++ "/log" ++ "/13selectedQueries") (showlines currentSelectedSequences)-          CE.evaluate currentSelectedSequences-        else do-          let fastaSelectedSequences = filterIdenticalSequences' alignmentSequences (95 :: Double)-          let currentSelectedSequenceIds = map (unSL . seqid) (take (queryNumber staticOptions) fastaSelectedSequences)-          stockholmSelectedSequences <- extractAlignmentSequencesByIds stockholmFilepath currentSelectedSequenceIds-          let currentSelectedSequences = if (blastSoftmaskingToggle staticOptions) then stockholmSelectedSequences else fastaSelectedSequences-          writeFile (tempDirPath staticOptions ++ show (iterationNumber modelConstruction) ++ "/log" ++ "/13selectedQueries") (showlines currentSelectedSequences)-          CE.evaluate currentSelectedSequences-    else return []---filterSequenceById :: [Sequence] -> L.ByteString-> [Sequence]-filterSequenceById alignmentSequences querySequenceId = filter (seqenceHasId querySequenceId) alignmentSequences--seqenceHasId :: L.ByteString -> Sequence -> Bool-seqenceHasId querySequenceId alignmentSequence = unSL (seqid alignmentSequence) == querySequenceId--constructModel :: ModelConstruction -> StaticOptions -> IO String-constructModel modelConstruction staticOptions = do-  --Extract sequences from modelconstruction-  let alignedSequences = extractAlignedSequences (iterationNumber modelConstruction) modelConstruction-  --The CM resides in the iteration directory where its input alignment originates from -  let outputDirectory = tempDirPath staticOptions ++ show (iterationNumber modelConstruction - 1) ++ "/"-  let alignmentSequences = map snd (V.toList (V.concat [alignedSequences]))-  --write Fasta sequences-  writeFasta (outputDirectory ++ "model" ++ ".fa") alignmentSequences-  let fastaFilepath = outputDirectory ++ "model" ++ ".fa"-  let locarnaFilepath = outputDirectory ++ "model" ++ ".mlocarna"-  let stockholmFilepath = outputDirectory ++ "model" ++ ".stockholm"-  --- let reformatedClustalFilepath = outputDirectory ++ "model" ++ ".clustal.reformated"-  let updatedStructureStockholmFilepath = outputDirectory ++ "newstructuremodel" ++ ".stockholm"-  let cmalignCMFilepath = tempDirPath staticOptions ++ show (iterationNumber modelConstruction - 2) ++ "/" ++ "model" ++ ".cm"-  let cmFilepath = outputDirectory ++ "model" ++ ".cm"-  let cmCalibrateFilepath = outputDirectory ++ "model" ++ ".cmcalibrate"-  let cmBuildFilepath = outputDirectory ++ "model" ++ ".cmbuild"-  let alifoldFilepath = outputDirectory ++ "model" ++ ".alifold"-  let refinedAlignmentFilepath = outputDirectory ++ "modelrefined" ++ ".stockholm"-  let cmBuildOptions ="--refine " ++ refinedAlignmentFilepath-  if alignmentModeInfernal modelConstruction-     then do-       logVerboseMessage (verbositySwitch staticOptions) "Construct Model - infernal mode\n" (tempDirPath staticOptions)-       systemCMalign ("--cpu " ++ show (cpuThreads staticOptions)) cmalignCMFilepath fastaFilepath stockholmFilepath-       systemRNAalifold "-r --cfactor 0.6 --nfactor 0.5" stockholmFilepath alifoldFilepath-       replaceStatus <- replaceStockholmStructure stockholmFilepath alifoldFilepath updatedStructureStockholmFilepath-       if null replaceStatus-         then do-           systemCMbuild cmBuildOptions updatedStructureStockholmFilepath cmFilepath cmBuildFilepath-           systemCMcalibrate "fast" (cpuThreads staticOptions) cmFilepath cmCalibrateFilepath-           return cmFilepath-         else do-           logWarning ("Warning: A problem occured updating the secondary structure of iteration " ++ show (iterationNumber modelConstruction)  ++ " stockholm alignment: " ++ replaceStatus) (tempDirPath staticOptions)-           systemCMbuild cmBuildOptions stockholmFilepath cmFilepath cmBuildFilepath-           systemCMcalibrate "fast" (cpuThreads staticOptions) cmFilepath cmCalibrateFilepath-           return cmFilepath-     else do-       logVerboseMessage (verbositySwitch staticOptions) "Construct Model - initial mode\n" (tempDirPath staticOptions)-       alignSequences "mlocarna" ("--threads=" ++ show (cpuThreads staticOptions) ++ " ") [fastaFilepath] [] [locarnaFilepath] []-       mlocarnaAlignment <- readStructuralClustalAlignment locarnaFilepath-       logEither mlocarnaAlignment (tempDirPath staticOptions)-       let stockholAlignment = convertClustaltoStockholm (fromRight mlocarnaAlignment)-       TI.writeFile stockholmFilepath stockholAlignment-       _ <- systemCMbuild cmBuildOptions stockholmFilepath cmFilepath cmBuildFilepath-       _ <- systemCMcalibrate "fast" (cpuThreads staticOptions) cmFilepath cmCalibrateFilepath-       return cmFilepath---- | Replaces structure of input stockholm file with the consensus structure of alifoldFilepath and outputs updated stockholmfile-replaceStockholmStructure :: String -> String -> String -> IO String-replaceStockholmStructure stockholmFilepath alifoldFilepath updatedStructureStockholmFilepath = do-  inputAln <- readFile stockholmFilepath-  inputRNAalifold <- readRNAalifold alifoldFilepath-  if isLeft inputRNAalifold-    then-     return (show (fromLeft inputRNAalifold))-    else do-     let alifoldstructure = alignmentConsensusDotBracket (fromRight inputRNAalifold)-     let seedLinesVector = V.fromList (lines inputAln)-     let structureIndices = V.toList (V.findIndices isStructureLine seedLinesVector)-     let updatedStructureElements = updateStructureElements seedLinesVector alifoldstructure structureIndices-     let newVector = seedLinesVector V.// updatedStructureElements-     let newVectorString = unlines (V.toList newVector)-     writeFile updatedStructureStockholmFilepath newVectorString-     return []--updateStructureElements :: V.Vector String -> String -> [Int] -> [(Int,String)]-updateStructureElements inputVector structureString indices-  | null indices = []-  | otherwise = newElement ++ updateStructureElements inputVector (drop structureLength structureString) (tail indices)-  where currentIndex = head indices-        currentElement = inputVector V.! currentIndex-        elementLength = length currentElement-        structureStartIndex = maximum (elemIndices ' ' currentElement) + 1-        structureLength = elementLength - structureStartIndex-        newElementHeader = take structureStartIndex currentElement-        newElementStructure = take structureLength structureString-        newElement = [(currentIndex,newElementHeader ++ newElementStructure)]--isStructureLine :: String -> Bool-isStructureLine input = "#=GC SS_cons" `isInfixOf` input---- Generates iteration string for Log-iterationSummaryLog :: ModelConstruction -> String-iterationSummaryLog mC = output-  where upperTaxonomyLimitOutput = maybe "not set" show (upperTaxonomyLimit mC)-        output = "Upper taxonomy id limit: " ++ upperTaxonomyLimitOutput ++ ", Collected members: " ++ show (length (concatMap sequenceRecords (taxRecords mC))) ++ "\n"---- | Used for passing progress to Alien server -iterationSummary :: ModelConstruction -> StaticOptions -> IO()-iterationSummary mC sO = do-  --iteration -- tax limit -- bitscore cutoff -- blastresult -- aligned seqs --queries --fa link --aln link --cm link-  let upperTaxonomyLimitOutput = maybe "not set" show (upperTaxonomyLimit mC)-  let output = show (iterationNumber mC) ++ "," ++ upperTaxonomyLimitOutput ++ "," ++ show (length (concatMap sequenceRecords (taxRecords mC)))-  writeFile (tempDirPath sO ++ "/log/" ++ show (iterationNumber mC) ++ ".log") output---- | Used for passing progress to Alien server -resultSummary :: ModelConstruction -> StaticOptions -> IO()-resultSummary mC sO = do-  --iteration -- tax limit -- bitscore cutoff -- blastresult -- aligned seqs --queries --fa link --aln link --cm link-  let upperTaxonomyLimitOutput = maybe "not set" show (upperTaxonomyLimit mC)-  let output = show (iterationNumber mC) ++ "," ++ upperTaxonomyLimitOutput ++ "," ++ show (length (concatMap sequenceRecords (taxRecords mC)))-  writeFile (tempDirPath sO ++ "/log/result" ++ ".log") output--readClustaloDistMatrix :: String -> IO (Either ParseError ([String],Matrix Double))-readClustaloDistMatrix = parseFromFile genParserClustaloDistMatrix--genParserClustaloDistMatrix :: GenParser Char st ([String],Matrix Double)-genParserClustaloDistMatrix = do-  _ <- many1 digit-  newline-  clustaloDistRow <- many1 (try genParserClustaloDistRow)-  eof-  return (map fst clustaloDistRow,fromLists (map snd clustaloDistRow))--genParserClustaloDistRow :: GenParser Char st (String,[Double])-genParserClustaloDistRow = do-  entryId <- many1 (noneOf " ")-  many1 space-  distances <- many1 (try genParserClustaloDistance)-  newline-  return (entryId,distances)--genParserClustaloDistance :: GenParser Char st Double-genParserClustaloDistance = do-  distance <- many1 (oneOf "1234567890.")-  optional (try (char ' ' ))-  return (readDouble distance)--getDistanceMatrixElements :: [String] -> Matrix Double -> String -> String -> Double-getDistanceMatrixElements ids distMatrix id1 id2 = distance-  -- Data.Matrix is indexed starting with 1-  where indexid1 = fromJust (elemIndex id1 ids) + 1-        indexid2 = fromJust (elemIndex id2 ids) + 1-        distance = getElem indexid1 indexid2 distMatrix---- | Filter duplicates removes hits in sequences that were already collected. This happens during revisiting the starting subtree.-filterDuplicates :: ModelConstruction -> SearchResult -> SearchResult-filterDuplicates modelConstruction inputSearchResult = uniqueSearchResult-  where alignedSequences = map snd (V.toList (extractAlignedSequences (iterationNumber modelConstruction) modelConstruction))-        collectedIdentifiers = map seqid alignedSequences-        uniques = filter (\(s,_,_) -> notElem (seqid s) collectedIdentifiers) (candidates inputSearchResult)-        uniqueSearchResult = SearchResult uniques (blastDatabaseSize inputSearchResult)---- | Filter a list of similar extended blast hits   ---filterIdenticalSequencesWithOrigin :: [(Sequence,Int,String,Char)] -> Double -> [(Sequence,Int,String,Char)]                            ---filterIdenticalSequencesWithOrigin (headSequence:rest) identitycutoff = result---  where filteredSequences = filter (\x -> (sequenceIdentity (firstOfQuadruple headSequence) (firstOfQuadruple x)) < identitycutoff) rest ---        result = headSequence:(filterIdenticalSequencesWithOrigin filteredSequences identitycutoff)---filterIdenticalSequencesWithOrigin [] _ = []---- | Filter a list of similar extended blast hits   -filterIdenticalSequences :: [(Sequence,Int,L.ByteString)] -> Double -> [(Sequence,Int,L.ByteString)]-filterIdenticalSequences (headSequence:rest) identitycutoff = result-  where filteredSequences = filter (\x -> sequenceIdentity (firstOfTriple headSequence) (firstOfTriple x) < identitycutoff) rest-        result = headSequence:filterIdenticalSequences filteredSequences identitycutoff-filterIdenticalSequences [] _ = []---- | Filter sequences too similar to already aligned sequences-filterWithCollectedSequences :: [(Sequence,Int,L.ByteString)] -> [Sequence] -> Double -> [(Sequence,Int,L.ByteString)]-filterWithCollectedSequences inputCandidates collectedSequences identitycutoff = filter (isUnSimilarSequence collectedSequences identitycutoff . firstOfTriple) inputCandidates---filterWithCollectedSequences [] [] _ = []---- | Filter alignment entries by similiarity  -filterIdenticalSequences' :: [Sequence] -> Double -> [Sequence]-filterIdenticalSequences' (headEntry:rest) identitycutoff = result-  where filteredEntries = filter (\ x -> sequenceIdentity headEntry x < identitycutoff) rest-        result = headEntry:filterIdenticalSequences' filteredEntries identitycutoff-filterIdenticalSequences' [] _ = []------ | Filter alignment entries by similiarity  ---filterIdenticalAlignmentEntry :: [ClustalAlignmentEntry] -> Double -> [ClustalAlignmentEntry]---filterIdenticalAlignmentEntry (headEntry:rest) identitycutoff = result---  where filteredEntries = filter (\x -> (stringIdentity (entryAlignedSequence headEntry) (entryAlignedSequence x)) < identitycutoff) rest---        result = headEntry:filterIdenticalAlignmentEntry filteredEntries identitycutoff---filterIdenticalAlignmentEntry [] _ = []--isUnSimilarSequence :: [Sequence] -> Double -> Sequence -> Bool-isUnSimilarSequence collectedSequences identitycutoff checkSequence = any (\ x -> sequenceIdentity checkSequence x < identitycutoff) collectedSequences--firstOfTriple :: (t, t1, t2) -> t-firstOfTriple (a,_,_) = a---- | Check if the result field of BlastResult is filled and if hits are present-blastMatchesPresent :: BlastResult -> Bool-blastMatchesPresent blastResult-  | null resultList = False-  | otherwise = True-  where resultList = concatMap matches (concatMap hits (results blastResult))---- | Compute identity of sequences-textIdentity :: T.Text -> T.Text -> Double-textIdentity text1 text2 = identityPercent-   where distance = TM.hamming text1 text2-         --Replication of RNAz select sequences requires only allowing substitutions-         --costs = ED.defaultEditCosts {ED.deletionCosts = ED.ConstantCost 100,ED.insertionCosts = ED.ConstantCost 100,ED.transpositionCosts = ED.ConstantCost 100}-         maximumDistance = maximum [T.length text1, T.length text2]-         distanceDouble = toInteger ( fromJust distance )-         identityPercent = 1 - (fromIntegral distanceDouble/fromIntegral maximumDistance)----- | Compute identity of sequences--- stringIdentity :: String -> String -> Double--- stringIdentity string1 string2 = identityPercent---    where distance = ED.levenshteinDistance costs string1 string2---          --Replication of RNAz select sequences requires only allowing substitutions---          costs = ED.defaultEditCosts {ED.deletionCosts = ED.ConstantCost 100,ED.insertionCosts = ED.ConstantCost 100,ED.transpositionCosts = ED.ConstantCost 100}---          maximumDistance = maximum [length string1,length string2]---          identityPercent = 1 - (fromIntegral distance/fromIntegral maximumDistance)---- | Compute identity of sequences-sequenceIdentity :: Sequence -> Sequence -> Double-sequenceIdentity sequence1 sequence2 = identityPercent-  where distance = ED.levenshteinDistance ED.defaultEditCosts sequence1string sequence2string-        sequence1string = L.unpack (unSD (seqdata sequence1))-        sequence2string = L.unpack (unSD (seqdata sequence2))-        maximumDistance = maximum [length sequence1string,length sequence2string]-        identityPercent = 100 - ((fromIntegral distance/fromIntegral maximumDistance) * (read "100" ::Double))--getTaxonomicContextEntrez :: Maybe Int -> Maybe Taxon -> IO (Maybe Taxon)-getTaxonomicContextEntrez upperTaxLimit currentTaxonomicContext =-  if isJust upperTaxLimit-      then if isJust currentTaxonomicContext-        then return currentTaxonomicContext-        else retrieveTaxonomicContextEntrez (fromJust upperTaxLimit)-          --return retrievedTaxonomicContext-    else return Nothing--setTaxonomicContextEntrez :: Int -> Maybe Taxon -> Maybe Int -> (Maybe Int, Maybe Int)-setTaxonomicContextEntrez currentIterationNumber currentTaxonomicContext subTreeTaxId-  | currentIterationNumber == 0 = (subTreeTaxId, Nothing)-  | otherwise = setUpperLowerTaxLimitEntrez (fromJust subTreeTaxId) (fromJust currentTaxonomicContext)---- setTaxonomic Context for next candidate search, the upper bound of the last search become the lower bound of the next-setUpperLowerTaxLimitEntrez :: Int -> Taxon -> (Maybe Int, Maybe Int)-setUpperLowerTaxLimitEntrez subTreeTaxId currentTaxonomicContext = (upperLimit,lowerLimit)-  where upperLimit = raiseTaxIdLimitEntrez subTreeTaxId currentTaxonomicContext-        lowerLimit = Just subTreeTaxId--raiseTaxIdLimitEntrez :: Int -> Taxon -> Maybe Int-raiseTaxIdLimitEntrez subTreeTaxId taxon = parentNodeTaxId-  where lastUpperBoundNodeIndex = fromJust (V.findIndex  (\node -> lineageTaxId node == subTreeTaxId) lineageExVector)-        linageNodeTaxId = Just (lineageTaxId (lineageExVector V.! (lastUpperBoundNodeIndex -1)))-        lineageExVector = V.fromList (lineageEx taxon)-        --the input taxid is not part of the lineage, therefor we look for further taxids in the lineage after we used the parent tax id of the input node-        parentNodeTaxId = if subTreeTaxId == taxonTaxId taxon then Just (taxonParentTaxId taxon) else linageNodeTaxId--constructNext :: Int -> ModelConstruction -> [(Sequence,Int,L.ByteString)] -> Maybe Int -> Maybe Taxon  -> [Sequence] -> [SearchResult] -> Bool -> ModelConstruction-constructNext currentIterationNumber modelconstruction alignmentResults upperTaxLimit inputTaxonomicContext inputSelectedQueries inputPotentialMembers toggleInfernalAlignmentModeTrue = nextModelConstruction-  where newIterationNumber = currentIterationNumber + 1-        taxEntries = taxRecords modelconstruction ++ buildTaxRecords alignmentResults currentIterationNumber-        potMembers = potentialMembers modelconstruction ++ inputPotentialMembers-        currentAlignmentMode = toggleInfernalAlignmentModeTrue || alignmentModeInfernal modelconstruction-        nextModelConstruction = ModelConstruction newIterationNumber (inputFasta modelconstruction) taxEntries upperTaxLimit inputTaxonomicContext (evalueThreshold modelconstruction) currentAlignmentMode inputSelectedQueries potMembers--buildTaxRecords :: [(Sequence,Int,L.ByteString)] -> Int -> [TaxonomyRecord]-buildTaxRecords alignmentResults currentIterationNumber = taxonomyRecords-  where taxIdGroups = groupBy sameTaxIdAlignmentResult alignmentResults-        taxonomyRecords = map (buildTaxRecord currentIterationNumber) taxIdGroups--sameTaxIdAlignmentResult :: (Sequence,Int,L.ByteString) -> (Sequence,Int,L.ByteString) -> Bool-sameTaxIdAlignmentResult (_,taxId1,_) (_,taxId2,_) = taxId1 == taxId2--buildTaxRecord :: Int -> [(Sequence,Int,L.ByteString)] -> TaxonomyRecord-buildTaxRecord currentIterationNumber entries = taxRecord-  where recordTaxId = (\(_,currentTaxonomyId,_) -> currentTaxonomyId) (head entries)-        seqRecords = map (buildSeqRecord currentIterationNumber)  entries-        taxRecord = TaxonomyRecord recordTaxId seqRecords--buildSeqRecord :: Int -> (Sequence,Int,L.ByteString) -> SequenceRecord-buildSeqRecord currentIterationNumber (parsedFasta,_,seqSubject) = SequenceRecord parsedFasta currentIterationNumber seqSubject---- | Partitions sequences by containing a cmsearch hit and extracts the hit region as new sequence-evaluePartitionTrimCMsearchHits :: Double -> [(CMsearch,(Sequence, Int, L.ByteString))] -> ([(CMsearch,(Sequence, Int, L.ByteString))],[(CMsearch,(Sequence, Int, L.ByteString))],[(CMsearch,(Sequence, Int, L.ByteString))])-evaluePartitionTrimCMsearchHits eValueThreshold cmSearchCandidatesWithSequences = (trimmedSelectedCandidates,potentialCandidates,rejectedCandidates)-  where potentialMemberseValueThreshold = eValueThreshold * 1000-        (prefilteredCandidates,rejectedCandidates) = partition (\(cmSearchResult,_) -> any (\hitScore' -> potentialMemberseValueThreshold >= hitEvalue hitScore') (cmsearchHits cmSearchResult)) cmSearchCandidatesWithSequences-        (selectedCandidates,potentialCandidates) = partition (\(cmSearchResult,_) -> any (\hitScore' -> eValueThreshold >= hitEvalue hitScore') (cmsearchHits cmSearchResult)) prefilteredCandidates-        trimmedSelectedCandidates = map (\(cmSearchResult,inputSequence) -> (cmSearchResult,trimCMsearchHit cmSearchResult inputSequence)) selectedCandidates---trimCMsearchHit :: CMsearch -> (Sequence, Int, L.ByteString) -> (Sequence, Int, L.ByteString)-trimCMsearchHit cmSearchResult (inputSequence,b,c) = (subSequence,b,c)-  where hitScoreEntry = head (cmsearchHits cmSearchResult)-        sequenceString = L.unpack (unSD (seqdata inputSequence))-        sequenceSubstring = cmSearchsubString (hitStart hitScoreEntry) (hitEnd hitScoreEntry) sequenceString-        --extend original seqheader-        newSequenceHeader =  L.pack (L.unpack (unSL (seqheader inputSequence)) ++ "cmS_" ++ show (hitStart hitScoreEntry) ++ "_" ++ show (hitEnd hitScoreEntry) ++ "_" ++ show (hitStrand hitScoreEntry))-        subSequence = Seq (SeqLabel newSequenceHeader) (SeqData (L.pack sequenceSubstring)) Nothing---- | Extract a substring with coordinates from cmsearch, first nucleotide has index 1-cmSearchsubString :: Int -> Int -> String -> String-cmSearchsubString startSubString endSubString inputString-  | startSubString < endSubString = take (endSubString - (startSubString -1))(drop (startSubString - 1) inputString)-  | startSubString > endSubString = take (reverseEnd - (reverseStart - 1))(drop (reverseStart - 1 ) (reverse inputString))-  | otherwise = take (endSubString - (startSubString -1))(drop (startSubString - 1) inputString)-  where stringLength = length inputString-        reverseStart = stringLength - (startSubString + 1)-        reverseEnd = stringLength - (endSubString - 1)--extractQueries :: Int -> ModelConstruction -> [Sequence]-extractQueries foundSequenceNumber modelconstruction-  | foundSequenceNumber < 3 = [fastaSeqData]-  | otherwise = querySequences'-  where fastaSeqData = inputFasta modelconstruction-        querySequences' = selectedQueries modelconstruction--extractQueryCandidates :: [(Sequence,Int,L.ByteString)] -> V.Vector (Int,Sequence)-extractQueryCandidates querycandidates = indexedSeqences-  where sequences = map (\(candidateSequence,_,_) -> candidateSequence) querycandidates-        indexedSeqences = V.map (\(number,candidateSequence) -> (number + 1,candidateSequence))(V.indexed (V.fromList sequences))--buildTaxFilterQuery :: Maybe Int -> Maybe Int -> String-buildTaxFilterQuery upperTaxLimit lowerTaxLimit-  | isNothing upperTaxLimit = ""-  | isNothing lowerTaxLimit =  "&ENTREZ_QUERY=" ++ encodedTaxIDQuery (fromJust upperTaxLimit)-  | otherwise = "&ENTREZ_QUERY=" ++ "%28txid" ++ show (fromJust upperTaxLimit)  ++ "%5BORGN%5D%29" ++ "NOT" ++ "%28txid" ++ show (fromJust lowerTaxLimit) ++ "%5BORGN%5D&EQ_OP%29"--buildHitNumberQuery :: String -> String-buildHitNumberQuery hitNumber-  | hitNumber == "" = ""-  | otherwise = "&ALIGNMENTS=" ++ hitNumber--encodedTaxIDQuery :: Int -> String-encodedTaxIDQuery taxID = "txid" ++ show taxID ++ "%20%5BORGN%5D&EQ_OP"---- | Adds cm prefix to pseudo random number-randomid :: Int16 -> String-randomid number = "cm" ++ show number---- | Create session id for RNAlien-createSessionID :: Maybe String -> IO String-createSessionID sessionIdentificator =-  if isJust sessionIdentificator-    then return (fromJust sessionIdentificator)-    else do-      randomNumber <- randomIO :: IO Int16-      let sessionId = randomid (abs (randomNumber))-      return sessionId---- | Run external locarna command and read the output into the corresponding datatype-systemlocarna :: String -> (String,String,String,String) -> IO ExitCode-systemlocarna options (inputFilePath1, inputFilePath2, clustalformatoutputFilePath, outputFilePath) = system ("locarna " ++ options ++ " --clustal=" ++ clustalformatoutputFilePath  ++ " " ++ inputFilePath1  ++ " " ++ inputFilePath2 ++ " > " ++ outputFilePath)---- | Run external mlocarna command and read the output into the corresponding datatype, there is also a folder created at the location of the input fasta file-systemMlocarna :: String -> (String,String) -> IO ExitCode-systemMlocarna options (inputFilePath, outputFilePath) = system ("mlocarna " ++ options ++ " " ++ inputFilePath ++ " > " ++ outputFilePath)---- | Run external mlocarna command and read the output into the corresponding datatype, there is also a folder created at the location of the input fasta file, the job is terminated after the timeout provided in seconds-systemMlocarnaWithTimeout :: String -> String -> (String,String) -> IO ExitCode-systemMlocarnaWithTimeout timeout options (inputFilePath, outputFilePath) = system ("timeout " ++ timeout ++"s "++ "mlocarna " ++ options ++ " " ++ inputFilePath ++ " > " ++ outputFilePath)---- | Run external clustalo command and return the Exitcode-systemClustalw2 :: String -> (String,String,String) -> IO ExitCode-systemClustalw2 options (inputFilePath, outputFilePath, summaryFilePath) = system ("clustalw2 " ++ options ++ "-INFILE=" ++ inputFilePath ++ " -OUTFILE=" ++ outputFilePath ++ ">" ++ summaryFilePath)---- | Run external clustalo command and return the Exitcode-systemClustalo :: String -> (String,String) -> IO ExitCode-systemClustalo options (inputFilePath, outputFilePath) = system ("clustalo " ++ options ++ "--infile=" ++ inputFilePath ++ " >" ++ outputFilePath)---- | Run external CMbuild command and read the output into the corresponding datatype -systemCMbuild ::  String -> String -> String -> String -> IO ExitCode-systemCMbuild options alignmentFilepath modelFilepath outputFilePath = system ("cmbuild " ++ options ++ " " ++ modelFilepath ++ " " ++ alignmentFilepath  ++ " > " ++ outputFilePath)---- | Run CMCompare and read the output into the corresponding datatype-systemCMcompare ::  String -> String -> String -> IO ExitCode-systemCMcompare model1path model2path outputFilePath = system ("CMCompare -q " ++ model1path ++ " " ++ model2path ++ " >" ++ outputFilePath)---- | Run CMsearch -systemCMsearch :: Int -> String -> String -> String -> String -> IO ExitCode-systemCMsearch cpus options covarianceModelPath sequenceFilePath outputPath = system ("cmsearch --notrunc --cpu " ++ show cpus ++ " " ++ options ++ " -g " ++ covarianceModelPath ++ " " ++ sequenceFilePath ++ "> " ++ outputPath)---- | Run CMstat-systemCMstat :: String -> String -> IO ExitCode-systemCMstat covarianceModelPath outputPath = system ("cmstat " ++ covarianceModelPath ++ " > " ++ outputPath)---- | Run CMcalibrate and return exitcode-systemCMcalibrate :: String -> Int -> String -> String -> IO ExitCode-systemCMcalibrate mode cpus covarianceModelPath outputPath-  | mode == "fast" = system ("cmcalibrate --beta 1E-4 --cpu " ++ show cpus ++ " " ++ covarianceModelPath ++ "> " ++ outputPath)-  | otherwise = system ("cmcalibrate --cpu " ++ show cpus ++ " " ++ covarianceModelPath ++ "> " ++ outputPath)----- | Run CMcalibrate and return exitcode-systemCMalign :: String -> String -> String -> String -> IO ExitCode-systemCMalign options filePathCovarianceModel filePathSequence filePathAlignment = system ("cmalign " ++ options ++ " " ++ filePathCovarianceModel ++ " " ++ filePathSequence ++ "> " ++ filePathAlignment)--compareCM :: String -> String -> String -> IO (Either String Double)-compareCM rfamCMPath resultCMpath outputDirectory = do-  let myOptions = defaultDecodeOptions {-      decDelimiter = fromIntegral (ord ' ')-  }-  let rfamCMFileName = FP.takeBaseName rfamCMPath-  let resultCMFileName = FP.takeBaseName resultCMpath-  let cmcompareResultPath = outputDirectory ++ rfamCMFileName ++ resultCMFileName ++ ".cmcompare"-  _ <- systemCMcompare rfamCMPath resultCMpath cmcompareResultPath-  inputCMcompare <- readFile cmcompareResultPath-  let singlespaceCMcompare = unwords(words inputCMcompare)-  let decodedCmCompareOutput = head (V.toList (fromRight (decodeWith myOptions NoHeader (L.pack singlespaceCMcompare) :: Either String (V.Vector [String]))))-  --two.cm   three.cm     27.996     19.500 CCCAAAGGGCCCAAAGGG (((...)))(((...))) (((...)))(((...))) [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17] [11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27]-  let bitscore1 = read (decodedCmCompareOutput !! 2) :: Double-  let bitscore2 = read (decodedCmCompareOutput !! 3) :: Double-  let minmax = minimum [bitscore1,bitscore2]-  return (Right minmax)--readInt :: String -> Int-readInt = read--readDouble :: String -> Double-readDouble = read--extractCandidateSequences :: [(Sequence,Int,L.ByteString)] -> V.Vector (Int,Sequence)-extractCandidateSequences candidates' = indexedSeqences-  where sequences = map (\(inputSequence,_,_) -> inputSequence) candidates'-        indexedSeqences = V.map (\(number,inputSequence) -> (number + 1,inputSequence))(V.indexed (V.fromList sequences))--extractAlignedSequences :: Int -> ModelConstruction ->  V.Vector (Int,Sequence)-extractAlignedSequences iterationnumber modelconstruction-  | iterationnumber == 0 =  V.map (\(number,seq') -> (number + 1,seq')) (V.indexed (V.fromList [inputSequence]))-  | otherwise = indexedSeqRecords-  where inputSequence = inputFasta modelconstruction-        seqRecordsperTaxrecord = map sequenceRecords (taxRecords modelconstruction)-        seqRecords = concat seqRecordsperTaxrecord-        --alignedSeqRecords = filter (\seqRec -> (aligned seqRec) > 0) seqRecords -        indexedSeqRecords = V.map (\(number,seq') -> (number + 1,seq')) (V.indexed (V.fromList (inputSequence : map nucleotideSequence seqRecords)))--filterByParentTaxId :: [(BlastHit,Int)] -> Bool -> [(BlastHit,Int)]-filterByParentTaxId blastHitsWithParentTaxId singleHitPerParentTaxId-  |  singleHitPerParentTaxId = singleBlastHitperParentTaxId-  |  otherwise = blastHitsWithParentTaxId-  where blastHitsWithParentTaxIdSortedByParentTaxId = sortBy compareTaxId blastHitsWithParentTaxId-        blastHitsWithParentTaxIdGroupedByParentTaxId = groupBy sameTaxId blastHitsWithParentTaxIdSortedByParentTaxId-        singleBlastHitperParentTaxId = map (maximumBy compareHitEValue) blastHitsWithParentTaxIdGroupedByParentTaxId--filterByHitLength :: [BlastHit] -> Int -> Bool -> [BlastHit]-filterByHitLength blastHits queryLength filterOn-  | filterOn = filteredBlastHits-  | otherwise = blastHits-  where filteredBlastHits = filter (hitLengthCheck queryLength) blastHits---- | Hits should have a compareable length to query-hitLengthCheck :: Int -> BlastHit -> Bool-hitLengthCheck queryLength blastHit = lengthStatus-  where  blastMatches = matches blastHit-         minHfrom = minimum (map h_from blastMatches)-         minHfromHSP = fromJust (find (\hsp -> minHfrom == h_from hsp) blastMatches)-         maxHto = maximum (map h_to blastMatches)-         maxHtoHSP = fromJust (find (\hsp -> maxHto == h_to hsp) blastMatches)-         minHonQuery = q_from minHfromHSP-         maxHonQuery = q_to maxHtoHSP-         startCoordinate = minHfrom - minHonQuery-         endCoordinate = maxHto + (queryLength - maxHonQuery)-         fullSeqLength = endCoordinate - startCoordinate-         lengthStatus = fullSeqLength < (queryLength * 3)--filterByCoverage :: [BlastHit] -> Int -> Bool -> [BlastHit]-filterByCoverage blastHits queryLength filterOn-  | filterOn = filteredBlastHits-  | otherwise = blastHits-  where filteredBlastHits = filter (coverageCheck queryLength) blastHits---- | Hits should have a compareable length to query-coverageCheck :: Int -> BlastHit -> Bool-coverageCheck queryLength blastHit = coverageStatus-  where  blastMatches = matches blastHit-         maxIdentity = fromIntegral (maximum (map (snd . Bio.BlastXML.identity) blastMatches))-         coverageStatus = (maxIdentity/fromIntegral queryLength)* (100 :: Double) >= (80 :: Double)---- | Wrapper for retrieveFullSequence that rerequests incomplete return sequees-retrieveFullSequences :: StaticOptions -> [(String,Int,Int,String,T.Text,Int,L.ByteString)] -> IO [(Sequence,Int,L.ByteString)]-retrieveFullSequences staticOptions requestedSequences = do-  fullSequences <- mapM (retrieveFullSequence (tempDirPath staticOptions)) requestedSequences-  if any (isNothing . firstOfTriple) fullSequences-    then do-      let fullSequencesWithRequestedSequences = zip fullSequences requestedSequences-      --let (failedRetrievals, successfulRetrievals) = partition (\x -> L.null (unSD (seqdata (firstOfTriple (fst x))))) fullSequencesWithRequestedSequences-      let (failedRetrievals, successfulRetrievals) = partition (isNothing . firstOfTriple . fst) fullSequencesWithRequestedSequences-      --we try to reretrieve failed entries once-      missingSequences <- mapM (retrieveFullSequence (tempDirPath staticOptions) .snd) failedRetrievals-      let (stillMissingSequences,reRetrievedSequences) = partition (isNothing . firstOfTriple) missingSequences-      logWarning ("Sequence retrieval failed: \n" ++ concatMap show stillMissingSequences ++ "\n") (tempDirPath staticOptions)-      let unwrappedRetrievals = map (\(x,y,z) -> (fromJust x,y,z))  (map fst successfulRetrievals ++ reRetrievedSequences)-      CE.evaluate unwrappedRetrievals-    else CE.evaluate (map (\(x,y,z) -> (fromJust x,y,z)) fullSequences)--retrieveFullSequence :: String -> (String,Int,Int,String,T.Text,Int,L.ByteString) -> IO (Maybe Sequence,Int,L.ByteString)-retrieveFullSequence temporaryDirectoryPath (nucleotideId,seqStart,seqStop,strand,_,taxid,subject') = do-  let program' = Just "efetch"-  let database' = Just "nucleotide"-  let registrationInfo = buildRegistration "RNAlien" "florian.eggenhofer@univie.ac.at"-  let queryString = "id=" ++ nucleotideId ++ "&seq_start=" ++ show seqStart ++ "&seq_stop=" ++ show seqStop ++ "&rettype=fasta" ++ "&strand=" ++ strand ++ registrationInfo-  let entrezQuery = EntrezHTTPQuery program' database' queryString-  result <- CE.catch (entrezHTTP entrezQuery)-              (\e -> do let err = show (e :: CE.IOException)-                        logWarning ("Warning: Full sequence retrieval failed:" ++ " " ++ err) temporaryDirectoryPath-                        return [])-  if null result-    then return (Nothing,taxid,subject')-    else-      if null ((mkSeqs . L.lines) (L.pack result))-        then return (Nothing,taxid,subject')-        else do-          let parsedFasta = head ((mkSeqs . L.lines) (L.pack result))-          if L.null (unSD (seqdata parsedFasta))-            then return (Nothing,taxid,subject')-            else CE.evaluate (Just parsedFasta,taxid,subject')--getRequestedSequenceElement :: Int -> (BlastHit,Int) -> (String,Int,Int,String,T.Text,Int,L.ByteString)-getRequestedSequenceElement queryLength (blastHit,taxid)-  | blastHitIsReverseComplement (blastHit,taxid) = getReverseRequestedSequenceElement queryLength (blastHit,taxid)-  | otherwise = getForwardRequestedSequenceElement queryLength (blastHit,taxid)--blastHitIsReverseComplement :: (BlastHit,Int) -> Bool-blastHitIsReverseComplement (blastHit,_) = isReverse-  where blastMatch = head (matches blastHit)-        firstHSPfrom = h_from blastMatch-        firstHSPto = h_to blastMatch-        isReverse = firstHSPfrom > firstHSPto--getForwardRequestedSequenceElement :: Int -> (BlastHit,Int) -> (String,Int,Int,String,T.Text,Int,L.ByteString)-getForwardRequestedSequenceElement queryLength (blastHit,taxid) = (geneIdentifier',startcoordinate,endcoordinate,strand,accession',taxid,subjectBlast)-   where    accession' = extractAccession blastHit-            subjectBlast = unSL (subject blastHit)-            geneIdentifier' = extractGeneId blastHit-            blastMatch = head (matches blastHit)-            blastHitOriginSequenceLength = slength blastHit-            minHfrom = h_from blastMatch-            maxHto = h_to blastMatch-            minHonQuery = q_from blastMatch-            maxHonQuery = q_to blastMatch-            --unsafe coordinates may exceed length of available sequence-            unsafestartcoordinate = minHfrom - minHonQuery-            unsafeendcoordinate = maxHto + (queryLength - maxHonQuery)-            startcoordinate = lowerBoundryCoordinateSetter 0 unsafestartcoordinate-            endcoordinate = upperBoundryCoordinateSetter blastHitOriginSequenceLength unsafeendcoordinate-            strand = "1"-            ---- -            --blastMatches = matches blastHit-            --blastHitOriginSequenceLength = slength blastHit-            --minHfrom = minimum (map h_from blastMatches)-            --minHfromHSP = fromJust (find (\hsp -> minHfrom == h_from hsp) blastMatches)-            --maxHto = maximum (map h_to blastMatches)-            --maxHtoHSP = fromJust (find (\hsp -> maxHto == h_to hsp) blastMatches)-            --minHonQuery = q_from minHfromHSP-            --maxHonQuery = q_to maxHtoHSP-            --unsafe coordinates may exceed length of available sequence-            --unsafestartcoordinate = minHfrom - minHonQuery -            --unsafeendcoordinate = maxHto + (queryLength - maxHonQuery) -            --startcoordinate = lowerBoundryCoordinateSetter 0 unsafestartcoordinate-            --endcoordinate = upperBoundryCoordinateSetter blastHitOriginSequenceLength unsafeendcoordinate -            --strand = "1"--lowerBoundryCoordinateSetter :: Int -> Int -> Int-lowerBoundryCoordinateSetter lowerBoundry currentValue-  | currentValue < lowerBoundry = lowerBoundry-  | otherwise = currentValue--upperBoundryCoordinateSetter :: Int -> Int -> Int-upperBoundryCoordinateSetter upperBoundry currentValue-  | currentValue > upperBoundry = upperBoundry-  | otherwise = currentValue--getReverseRequestedSequenceElement :: Int -> (BlastHit,Int) -> (String,Int,Int,String,T.Text,Int,L.ByteString)-getReverseRequestedSequenceElement queryLength (blastHit,taxid) = (geneIdentifier',startcoordinate,endcoordinate,strand,accession',taxid,subjectBlast)-   where   accession' = extractAccession blastHit-           subjectBlast = unSL (subject blastHit)-           geneIdentifier' = extractGeneId blastHit-           blastMatch = head (matches blastHit)-           blastHitOriginSequenceLength = slength blastHit-           maxHfrom = h_from blastMatch-           minHto = h_to blastMatch-           minHonQuery = q_from blastMatch-           maxHonQuery = q_to blastMatch-           --unsafe coordinates may exceed length of avialable sequence-           unsafestartcoordinate = maxHfrom + minHonQuery-           unsafeendcoordinate = minHto - (queryLength - maxHonQuery)-           startcoordinate = lowerBoundryCoordinateSetter 0 unsafeendcoordinate-           endcoordinate = upperBoundryCoordinateSetter blastHitOriginSequenceLength unsafestartcoordinate-           strand = "2"-           ---           --blastMatches = matches blastHit-           --blastHitOriginSequenceLength = slength blastHit               -           --maxHfrom = maximum (map h_from blastMatches)-           --maxHfromHSP = fromJust (find (\hsp -> maxHfrom == h_from hsp) blastMatches)     -           --minHto = minimum (map h_to blastMatches)-           --minHtoHSP = fromJust (find (\hsp -> minHto == h_to hsp) blastMatches)-           --minHonQuery = q_from maxHfromHSP-           --maxHonQuery = q_to minHtoHSP-           --unsafe coordinates may exeed length of avialable sequence-           --unsafestartcoordinate = maxHfrom + minHonQuery -           --unsafeendcoordinate = minHto - (queryLength - maxHonQuery) -           --startcoordinate = lowerBoundryCoordinateSetter 0 unsafeendcoordinate -           --endcoordinate = upperBoundryCoordinateSetter blastHitOriginSequenceLength unsafestartcoordinate -           --strand = "2"----computeAlignmentSCIs :: [String] -> [String] -> IO ()---computeAlignmentSCIs alignmentFilepaths rnazOutputFilepaths = do---  let zippedFilepaths = zip alignmentFilepaths rnazOutputFilepaths---  mapM_ systemRNAz zippedFilepaths  --alignSequences :: String -> String -> [String] -> [String] -> [String] -> [String] -> IO ()-alignSequences program' options fastaFilepaths fastaFilepaths2 alignmentFilepaths summaryFilepaths = do-  let zipped4Filepaths = zip4 fastaFilepaths fastaFilepaths2 alignmentFilepaths summaryFilepaths-  let zipped3Filepaths = zip3 fastaFilepaths alignmentFilepaths summaryFilepaths-  let zippedFilepaths = zip fastaFilepaths alignmentFilepaths-  let timeout = "3600"-  case program' of-    "locarna" -> mapM_ (systemlocarna options) zipped4Filepaths-    "mlocarna" -> mapM_ (systemMlocarna options) zippedFilepaths-    "mlocarnatimeout" -> mapM_ (systemMlocarnaWithTimeout timeout options) zippedFilepaths-    "clustalo" -> mapM_ (systemClustalo options) zippedFilepaths-    _ -> mapM_ (systemClustalw2 options ) zipped3Filepaths--constructFastaFilePaths :: String -> (Int, Sequence) -> String-constructFastaFilePaths currentDirectory (fastaIdentifier, _) = currentDirectory ++ show fastaIdentifier ++".fa"--constructCMsearchFilePaths :: String -> (Int, Sequence) -> String-constructCMsearchFilePaths currentDirectory (fastaIdentifier, _) = currentDirectory ++ show fastaIdentifier ++".cmsearch"---- Smaller e-Values are greater, the maximum function is applied-compareHitEValue :: (BlastHit,Int) -> (BlastHit,Int) -> Ordering-compareHitEValue (hit1,_) (hit2,_)-  | hitEValue hit1 > hitEValue hit2 = LT-  | hitEValue hit1 < hitEValue hit2 = GT-  -- in case of equal evalues the first hit is selected-  | hitEValue hit1 == hitEValue hit2 = GT--- comparing (hitEValue . Down . fst)-compareHitEValue (_,_) (_,_) = EQ--compareTaxId :: (BlastHit,Int) -> (BlastHit,Int) -> Ordering-compareTaxId (_,taxId1) (_,taxId2)-  | taxId1 > taxId2 = LT-  | taxId1 < taxId2 = GT-  -- in case of equal evalues the first hit is selected-  | taxId1 == taxId2 = EQ-compareTaxId (_,_)  (_,_) = EQ--sameTaxId :: (BlastHit,Int) -> (BlastHit,Int) -> Bool-sameTaxId (_,taxId1) (_,taxId2) = taxId1 == taxId2---- | NCBI uses the e-Value of the best HSP as the Hits e-Value-hitEValue :: BlastHit -> Double-hitEValue hit = minimum (map e_val (matches hit))--convertFastaFoldStockholm :: Sequence -> String -> String-convertFastaFoldStockholm fastasequence foldedStructure = stockholmOutput-  where alnHeader = "# STOCKHOLM 1.0\n\n"-        --(L.unpack (unSL (seqheader inputFasta')))) ++ "\n" ++ (map toUpper (L.unpack (unSD (seqdata inputFasta')))) ++ "\n"-        seqIdentifier = L.unpack (unSL (seqheader fastasequence))-        seqSequence = L.unpack (unSD (seqdata fastasequence))-        identifierLength = length seqIdentifier-        spacerLength' = maximum [14,identifierLength + 2]-        spacer = replicate (spacerLength' - identifierLength) ' '-        entrystring = seqIdentifier ++ spacer ++ seqSequence ++ "\n"-        structureString = "#=GC SS_cons" ++ replicate (spacerLength' - 12) ' ' ++ foldedStructure ++ "\n"-        bottom = "//"-        stockholmOutput = alnHeader ++ entrystring ++ structureString ++ bottom--convertClustaltoStockholm :: StructuralClustalAlignment -> T.Text-convertClustaltoStockholm parsedMlocarnaAlignment = stockholmOutput-  where alnHeader = T.pack "# STOCKHOLM 1.0\n\n"-        clustalAlignment = structuralAlignmentEntries parsedMlocarnaAlignment-        uniqueIds = nub (map entrySequenceIdentifier clustalAlignment)-        mergedEntries = map (mergeEntry clustalAlignment) uniqueIds-        maxIdentifierLenght = maximum (map (T.length . entrySequenceIdentifier) clustalAlignment)-        spacerLength' = maxIdentifierLenght + 2-        stockholmEntries = T.concat (map (buildStockholmAlignmentEntries spacerLength') mergedEntries)-        structureString = T.pack "#=GC SS_cons" `T.append` T.replicate (spacerLength' - 12) (T.pack " ")  `T.append` secondaryStructureTrack parsedMlocarnaAlignment `T.append` T.pack "\n"-        bottom = T.pack "//"-        stockholmOutput = alnHeader `T.append` stockholmEntries `T.append` structureString `T.append` bottom--mergeEntry :: [ClustalAlignmentEntry] -> T.Text -> ClustalAlignmentEntry-mergeEntry clustalAlignment uniqueId = mergedEntry-  where idEntries = filter (\entry -> entrySequenceIdentifier entry==uniqueId) clustalAlignment-        mergedSeq = foldr (T.append . entryAlignedSequence) (T.pack "") idEntries-        mergedEntry = ClustalAlignmentEntry uniqueId mergedSeq--buildStockholmAlignmentEntries :: Int -> ClustalAlignmentEntry -> T.Text-buildStockholmAlignmentEntries inputSpacerLength entry = entrystring-  where idLength = T.length (T.filter (/= '\n') (entrySequenceIdentifier entry))-        spacer = T.replicate (inputSpacerLength - idLength) (T.pack " ")-        entrystring = entrySequenceIdentifier entry `T.append` spacer `T.append` entryAlignedSequence entry `T.append` T.pack "\n"--retrieveTaxonomicContextEntrez :: Int -> IO (Maybe Taxon)-retrieveTaxonomicContextEntrez inputTaxId = do-       let program' = Just "efetch"-       let database' = Just "taxonomy"-       let taxIdString = show inputTaxId-       let registrationInfo = buildRegistration "RNAlien" "florian.eggenhofer@univie.ac.at"-       let queryString = "id=" ++ taxIdString ++ registrationInfo-       let entrezQuery = EntrezHTTPQuery program' database' queryString-       result <- entrezHTTP entrezQuery-       if null result-          then do-            error "Could not retrieve taxonomic context from NCBI Entrez, cannot proceed."-            return Nothing-          else do-            let taxon = head (readEntrezTaxonSet result)-            --print taxon-            if null (lineageEx taxon)-              then error "Retrieved taxonomic context taxon from NCBI Entrez with empty lineage, cannot proceed."-              else return (Just taxon)--retrieveParentTaxIdEntrez :: [(BlastHit,Int)] -> IO [(BlastHit,Int)]-retrieveParentTaxIdEntrez blastHitsWithHitTaxids =-  if not (null blastHitsWithHitTaxids)-     then do-       let program' = Just "efetch"-       let database' = Just "taxonomy"-       let extractedBlastHits = map fst blastHitsWithHitTaxids-       let taxIds = map snd blastHitsWithHitTaxids-       let taxIdStrings = map show taxIds-       let taxIdQuery = intercalate "," taxIdStrings-       let registrationInfo = buildRegistration "RNAlien" "florian.eggenhofer@univie.ac.at"-       let queryString = "id=" ++ taxIdQuery ++ registrationInfo-       let entrezQuery = EntrezHTTPQuery program' database' queryString-       result <- entrezHTTP entrezQuery-       let parentTaxIds = readEntrezParentIds result-       if null parentTaxIds-         then return []-         else CE.evaluate (zip extractedBlastHits parentTaxIds)-    else return []---- | Wrapper functions that ensures that only 20 queries are sent per request-retrieveParentTaxIdsEntrez :: [(BlastHit,Int)] -> IO [(BlastHit,Int)]-retrieveParentTaxIdsEntrez taxIdwithBlastHits = do-  let splits = portionListElements taxIdwithBlastHits 20-  taxIdsOutput <- mapM retrieveParentTaxIdEntrez splits-  return (concat taxIdsOutput)---- | Wrapper functions that ensures that only 20 queries are sent per request-retrieveBlastHitsTaxIdEntrez :: [BlastHit] -> IO [([BlastHit],String)]-retrieveBlastHitsTaxIdEntrez blastHits = do-  let splits = portionListElements blastHits 20-  mapM retrieveBlastHitTaxIdEntrez splits---retrieveBlastHitTaxIdEntrez :: [BlastHit] -> IO ([BlastHit],String)-retrieveBlastHitTaxIdEntrez blastHits =-  if not (null blastHits)-     then do-       let geneIds = map extractGeneId blastHits-       let idList = intercalate "," geneIds-       let registrationInfo = buildRegistration "RNAlien" "florian.eggenhofer@univie.ac.at"-       let query' = "id=" ++ idList ++ registrationInfo-       let entrezQuery = EntrezHTTPQuery (Just "esummary") (Just "nucleotide") query'-       threadDelay 10000000-       result <- entrezHTTP entrezQuery-       CE.evaluate (blastHits,result)-     else return (blastHits,"")--extractTaxIdFromEntrySummaries :: String -> [Int]-extractTaxIdFromEntrySummaries input-  | null input = []-  | null parsedResultList = []-  | otherwise = hitTaxIds-  where parsedResultList = readEntrezSummaries input-        parsedResult = head parsedResultList-        blastHitSummaries = documentSummaries parsedResult-        hitTaxIdStrings = map extractTaxIdfromDocumentSummary blastHitSummaries-        hitTaxIds = map readInt hitTaxIdStrings--extractAccession :: BlastHit -> T.Text-extractAccession currentBlastHit = accession'-  where splitedFields = T.splitOn (T.pack "|") (DTE.decodeUtf8 (L.toStrict (hitId currentBlastHit)))-        accession' =  splitedFields !! 3--extractGeneId :: BlastHit -> String-extractGeneId currentBlastHit = nucleotideId-  where truncatedId = drop 3 (L.unpack (hitId currentBlastHit))-        pipeSymbolIndex = fromJust (elemIndex '|' truncatedId)-        nucleotideId = take pipeSymbolIndex truncatedId--extractTaxIdfromDocumentSummary :: EntrezDocSum -> String-extractTaxIdfromDocumentSummary documentSummary = itemContent (fromJust (find (\item -> "TaxId" == itemName item) (summaryItems documentSummary)))--getBestHit :: BlastResult -> BlastHit-getBestHit blastResult-  | null (concatMap hits (results blastResult)) = error "getBestHit - head: empty list"-  | otherwise = head (hits (head (results blastResult)))---- Blast returns low evalues with zero instead of the exact number-getHitWithFractionEvalue :: BlastResult -> Maybe BlastMatch-getHitWithFractionEvalue blastResult-  | null (concatMap hits (results blastResult)) = Nothing-  | otherwise = find (\match -> e_val match /= (0 ::Double)) (concatMap matches (concatMap hits (results blastResult)))--showlines :: Show a => [a] -> String-showlines = concatMap (\x -> show x ++ "\n")--logMessage :: String -> String -> IO ()-logMessage logoutput temporaryDirectoryPath = appendFile (temporaryDirectoryPath ++ "Log") logoutput--logWarning :: String -> String -> IO ()-logWarning logoutput temporaryDirectoryPath = appendFile (temporaryDirectoryPath ++ "log/warnings") logoutput--logVerboseMessage :: Bool -> String -> String -> IO ()-logVerboseMessage verboseTrue logoutput temporaryDirectoryPath-  | verboseTrue = appendFile (temporaryDirectoryPath ++ "Log") (show logoutput)-  | otherwise = return ()--logEither :: (Show a) => Either a b -> String -> IO ()-logEither (Left logoutput) temporaryDirectoryPath = appendFile (temporaryDirectoryPath ++ "Log") (show logoutput)-logEither  _ _ = return ()--checkTools :: [String] -> String -> String -> IO (Either String String)-checkTools tools temporaryDirectoryPath selectedQuerySelectionMethod = do-  -- if queryselectionmethod is set to clustering then also check for clustal omega-  let additionaltools = if selectedQuerySelectionMethod == "clustering" then tools ++ ["clustalo"] else tools-  -- check if all tools are available via PATH or Left-  checks <- mapM checkTool additionaltools-  if not (null (lefts checks))-    then return (Left (concat (lefts checks)))-    else do-      logMessage ("Tools : " ++ intercalate "," tools ++ "\n") temporaryDirectoryPath-      return (Right "Tools ok")--logToolVersions :: String -> String -> IO ()-logToolVersions inputQuerySelectionMethod temporaryDirectoryPath = do-  let clustaloversionpath = temporaryDirectoryPath ++ "log/clustalo.version"-  let mlocarnaversionpath = temporaryDirectoryPath ++ "log/mlocarna.version"-  let rnafoldversionpath = temporaryDirectoryPath ++ "log/RNAfold.version"-  let infernalversionpath = temporaryDirectoryPath ++ "log/Infernal.version"-  --_ <- system ("clustalo --version >" ++ clustaloversionpath)-  _ <- system ("mlocarna --version >" ++ mlocarnaversionpath)-  _ <- system ("RNAfold --version >" ++ rnafoldversionpath)-  _ <- system ("cmcalibrate -h >" ++ infernalversionpath)-  -- _ <- system ("RNAz" ++ rnazversionpath)-  -- _ <- system ("CMCompare >" ++ infernalversionpath)-  mlocarnaversion <- readFile mlocarnaversionpath-  rnafoldversion <- readFile rnafoldversionpath-  infernalversionOutput <- readFile infernalversionpath-  let infernalversion = lines infernalversionOutput !! 1-  if inputQuerySelectionMethod == "clustering"-     then do-       _ <- system ("clustalo --version >" ++ clustaloversionpath)-       clustaloversion <- readFile clustaloversionpath-       let messageString = "Clustalo version: " ++ clustaloversion ++ "mlocarna version: " ++ mlocarnaversion  ++ "RNAfold version: " ++ rnafoldversion  ++ "infernalversion: " ++ infernalversion ++ "\n"-       logMessage messageString temporaryDirectoryPath-     else do-       let messageString = "mlocarna version: " ++ mlocarnaversion  ++ "RNAfold version: " ++ rnafoldversion  ++ "infernalversion: " ++ infernalversion ++ "\n"-       logMessage messageString temporaryDirectoryPath---checkTool :: String -> IO (Either String String)-checkTool tool = do-  toolcheck <- findExecutable tool-  if isJust toolcheck-    then return (Right (fromJust toolcheck))-    else return (Left ("RNAlien could not find "++ tool ++ " in your $PATH and has to abort.\n"))--constructTaxonomyRecordsCSVTable :: ModelConstruction -> String-constructTaxonomyRecordsCSVTable modelconstruction = csvtable-  where tableheader = "Taxonomy Id;Added in Iteration Step;Entry Header\n"-        tablebody = concatMap constructTaxonomyRecordCSVEntries (taxRecords modelconstruction)-        csvtable = tableheader ++ tablebody--constructTaxonomyRecordCSVEntries :: TaxonomyRecord -> String-constructTaxonomyRecordCSVEntries taxRecord = concatMap (constructTaxonomyRecordCSVEntry taxIdString) (sequenceRecords taxRecord)-  where taxIdString = show (recordTaxonomyId taxRecord)--constructTaxonomyRecordCSVEntry :: String -> SequenceRecord -> String-constructTaxonomyRecordCSVEntry taxIdString seqrec = taxIdString ++ ";" ++ show (aligned seqrec) ++ ";" ++ filter checkTaxonomyRecordCSVChar (L.unpack (unSL (seqheader (nucleotideSequence seqrec)))) ++ "\n"--checkTaxonomyRecordCSVChar :: Char -> Bool-checkTaxonomyRecordCSVChar c-  | c == '"' = False-  | c == ';' = False-  | otherwise = True--setVerbose :: Verbosity -> Bool-setVerbose verbosityLevel-  | verbosityLevel == Loud = True-  | otherwise = False--evaluateConstructionResult :: StaticOptions -> ModelConstruction -> IO String-evaluateConstructionResult staticOptions mCResult = do-  let evaluationDirectoryFilepath = tempDirPath staticOptions ++ "evaluation/"-  createDirectoryIfMissing False evaluationDirectoryFilepath-  let reformatedClustalPath = evaluationDirectoryFilepath ++ "result.clustal.reformated"-  let cmFilepath = tempDirPath staticOptions ++ "result.cm"-  let resultSequences = inputFasta mCResult:map nucleotideSequence (concatMap sequenceRecords (taxRecords mCResult))-  let resultNumber = length resultSequences-  let rnaCentralQueries = map RCH.buildSequenceViaMD5Query resultSequences-  rnaCentralEntries <- RCH.getRNACentralEntries rnaCentralQueries-  let rnaCentralEvaluationResult = RCH.showRNAcentralAlienEvaluation rnaCentralEntries-  writeFile (tempDirPath staticOptions ++ "result.rnacentral") rnaCentralEvaluationResult-  let resultModelStatistics = tempDirPath staticOptions ++ "result.cmstat"-  systemCMstat cmFilepath resultModelStatistics-  inputcmStat <- readCMstat resultModelStatistics-  let cmstatString = cmstatEvalOutput inputcmStat-  if resultNumber > 1-    then do-      let resultRNAz = tempDirPath staticOptions ++ "result.rnaz"-      let resultRNAcode = tempDirPath staticOptions ++ "result.rnacode"-      let resultClustalFilepath = tempDirPath staticOptions ++ "result.clustal"-      let seqNumber = 6 :: Int-      let optimalIdentity = 80 :: Double-      let maximalIdentity = 99 :: Double-      let referenceSequence = True-      preprocessingOutput <- preprocessClustalForRNAz resultClustalFilepath reformatedClustalPath seqNumber optimalIdentity maximalIdentity referenceSequence-      if isRight preprocessingOutput-        then do-          let rightPreprocessingOutput = fromRight preprocessingOutput-          let rnazClustalpath = snd rightPreprocessingOutput-          systemRNAz "-l" rnazClustalpath resultRNAz-          inputRNAz <- readRNAz resultRNAz-          let rnaZString = rnaZEvalOutput inputRNAz-          RC.systemRNAcode " -t " rnazClustalpath resultRNAcode-          inputRNAcode <- RC.readRNAcodeTabular resultRNAcode-          let rnaCodeString = rnaCodeEvalOutput inputRNAcode-          return ("\nEvaluation of RNAlien result :\nCMstat statistics for result.cm\n" ++ cmstatString ++ "\nRNAz statistics for result alignment: " ++ rnaZString ++ "\nRNAcode output for result alignment:\n" ++ rnaCodeString ++ "\nSequences found by RNAlien with RNAcentral entry:\n" ++ rnaCentralEvaluationResult)-        else do-          logWarning ("Running RNAz for result evalution encountered a problem:" ++ fromLeft preprocessingOutput) (tempDirPath staticOptions)-          return ("\nEvaluation of RNAlien result :\nCMstat statistics for result.cm\n" ++ cmstatString ++ "\nRNAz statistics for result alignment: Running RNAz for result evalution encountered a problem\n" ++ fromLeft preprocessingOutput ++ "\n" ++ "Sequences found by RNAlien with RNAcentral entry:\n" ++ rnaCentralEvaluationResult)-    else do-      logWarning "Message: RNAlien could not find additional covariant sequences\n Could not run RNAz statistics. Could not run RNAz statistics with a single sequence.\n" (tempDirPath staticOptions)-      return ("\nEvaluation of RNAlien result :\nCMstat statistics for result.cm\n" ++ cmstatString ++ "\nRNAlien could not find additional covariant sequences. Could not run RNAz statistics with a single sequence.\n\nSequences found by RNAlien with RNAcentral entry:\n" ++ rnaCentralEvaluationResult)---cmstatEvalOutput :: Either ParseError CMstat -> String-cmstatEvalOutput inputcmstat-  | isRight inputcmstat = cmstatString-  | otherwise = show (fromLeft inputcmstat)-    where cmStat = fromRight inputcmstat-          cmstatString = "  Sequence Number: " ++ show (statSequenceNumber cmStat)++ "\n" ++ "  Effective Sequences: " ++ show (statEffectiveSequences cmStat)++ "\n" ++ "  Consensus length: " ++ show (statConsensusLength cmStat) ++ "\n" ++ "  Expected maximum hit-length: " ++ show (statW cmStat) ++ "\n" ++ "  Basepairs: " ++ show (statBasepairs cmStat)++ "\n" ++ "  Bifurcations: " ++ show (statBifurcations cmStat) ++ "\n" ++ "  Modeltype: " ++ show (statModel cmStat) ++ "\n" ++ "  Relative Entropy CM: " ++ show (relativeEntropyCM cmStat) ++ "\n" ++ "  Relative Entropy HMM: " ++ show (relativeEntropyHMM cmStat) ++ "\n"--rnaZEvalOutput :: Either ParseError RNAz -> String-rnaZEvalOutput inputRNAz-  | isRight inputRNAz = rnazString-  | otherwise = show (fromLeft inputRNAz)-    where rnaZ = fromRight inputRNAz-          rnazString = "  Mean pairwise identity: " ++ show (meanPairwiseIdentity rnaZ) ++ "\n  Shannon entropy: " ++ show (shannonEntropy rnaZ) ++  "\n  GC content: " ++ show (gcContent rnaZ) ++ "\n  Mean single sequence minimum free energy: " ++ show (meanSingleSequenceMinimumFreeEnergy rnaZ) ++ "\n  Consensus minimum free energy: " ++ show (consensusMinimumFreeEnergy rnaZ) ++ "\n  Energy contribution: " ++ show (energyContribution rnaZ) ++ "\n  Covariance contribution: " ++ show (covarianceContribution rnaZ) ++ "\n  Combinations pair: " ++ show (combinationsPair rnaZ) ++ "\n  Mean z-score: " ++ show (meanZScore rnaZ) ++ "\n  Structure conservation index: " ++ show (structureConservationIndex rnaZ) ++ "\n  Background model: " ++ backgroundModel rnaZ ++ "\n  Decision model: " ++ decisionModel rnaZ ++ "\n  SVM decision value: " ++ show (svmDecisionValue rnaZ) ++ "\n  SVM class propability: " ++ show (svmRNAClassProbability rnaZ) ++ "\n  Prediction: " ++ prediction rnaZ--rnaCodeEvalOutput :: Either ParseError RC.RNAcode -> String-rnaCodeEvalOutput inputRNAcode-  | isRight inputRNAcode = rnaCodeString-  | otherwise = show (fromLeft inputRNAcode)-    where rnaCode = fromRight inputRNAcode-          rnaCodeString = "HSS\tFrame\tLength\tFrom\tTo\tName\tStart\tEnd\tScore\tP\n" ++ rnaCodeEntries-          rnaCodeEntries = concatMap showRNACodeHits (RC.rnacodeHits rnaCode)--showRNACodeHits :: RC.RNAcodeHit -> String-showRNACodeHits rnacodeHit = show (RC.hss rnacodeHit) ++ "\t" ++ show (RC.frame rnacodeHit) ++ "\t" ++ show (RC.hitLength rnacodeHit) ++ "\t"++ show (RC.from rnacodeHit) ++ "\t" ++ show (RC.to rnacodeHit) ++ "\t" ++ RC.name rnacodeHit ++ "\t" ++ show (RC.start rnacodeHit) ++ "\t" ++ show (RC.end rnacodeHit) ++ "\t" ++ show (RC.score rnacodeHit) ++ show (RC.pvalue rnacodeHit) ++ "\n"---- | Call for external preprocessClustalForRNAz-preprocessClustalForRNAzExternal :: String -> String -> Int -> Int -> Int -> Bool -> IO (Either String (String,String))-preprocessClustalForRNAzExternal clustalFilepath reformatedClustalPath seqenceNumber optimalIdentity maximalIdenity referenceSequence = do-  clustalText <- TI.readFile clustalFilepath-  --change clustal format for rnazSelectSeqs.pl-  let reformatedClustalText = T.map reformatAln clustalText-  TI.writeFile reformatedClustalPath reformatedClustalText-  --select representative entries from result.Clustal with select_sequences-  let selectedClustalpath = clustalFilepath ++ ".selected"-  let sequenceNumberOption = " -n "  ++ show seqenceNumber ++ " "-  let optimalIdentityOption = " -i "  ++ show optimalIdentity  ++ " "-  let maximalIdentityOption = " --max-id="  ++ show maximalIdenity  ++ " "-  let referenceSequenceOption = if referenceSequence then " " else " -x "-  let syscall = "rnazSelectSeqs.pl " ++ reformatedClustalPath ++ " " ++ sequenceNumberOption ++ optimalIdentityOption ++ maximalIdentityOption ++ referenceSequenceOption ++  " >" ++ selectedClustalpath-  --putStrLn syscall-  system syscall-  selectedClustalText <- readFile selectedClustalpath-  return (Right ([],selectedClustalText))---- | Call for external preprocessClustalForRNAcode - RNAcode additionally to RNAz requirements does not accept pipe,underscore, doublepoint symbols-preprocessClustalForRNAcodeExternal :: String -> String -> Int -> Int -> Int -> Bool -> IO (Either String (String,String))-preprocessClustalForRNAcodeExternal clustalFilepath reformatedClustalPath seqenceNumber optimalIdentity maximalIdenity referenceSequence = do-  clustalText <- TI.readFile clustalFilepath-  --change clustal format for rnazSelectSeqs.pl-  let clustalTextLines = T.lines clustalText-  let headerClustalTextLines = T.unlines (take 2 clustalTextLines)-  let headerlessClustalTextLines = T.unlines (drop 2 clustalTextLines)-  let reformatedClustalText = T.map reformatRNACodeAln headerlessClustalTextLines-  TI.writeFile reformatedClustalPath (headerClustalTextLines `T.append` T.singleton '\n' `T.append` reformatedClustalText)-  --select representative entries from result.Clustal with select_sequences-  let selectedClustalpath = clustalFilepath ++ ".selected"-  let sequenceNumberOption = " -n "  ++ show seqenceNumber  ++ " "-  let optimalIdentityOption = " -i "  ++ show optimalIdentity  ++ " "-  let maximalIdentityOption = " --max-id="  ++ show maximalIdenity  ++ " "-  let referenceSequenceOption = if referenceSequence then " " else " -x "-  let syscall = "rnazSelectSeqs.pl " ++ reformatedClustalPath ++ " " ++ sequenceNumberOption ++ optimalIdentityOption ++ maximalIdentityOption ++ referenceSequenceOption ++  " >" ++ selectedClustalpath-  --putStrLn syscall-  system syscall-  selectedClustalText <- readFile selectedClustalpath-  return (Right ([],selectedClustalText))--preprocessClustalForRNAz :: String -> String -> Int -> Double -> Double -> Bool -> IO (Either String (String,String))-preprocessClustalForRNAz clustalFilepath _ seqenceNumber optimalIdentity maximalIdenity referenceSequence = do-  clustalText <- TI.readFile clustalFilepath-  let clustalTextLines = T.lines clustalText-  parsedClustalInput <- readClustalAlignment clustalFilepath-  let selectedClustalpath = clustalFilepath ++ ".selected"-  if length clustalTextLines > 5-    then-      if isRight parsedClustalInput-        then do-          let (idMatrix,filteredClustalInput) = rnaCodeSelectSeqs2 (fromRight parsedClustalInput) seqenceNumber optimalIdentity maximalIdenity referenceSequence-          writeFile selectedClustalpath (show filteredClustalInput)-          let formatedIdMatrix = show (fmap formatIdMatrix idMatrix)-          return (Right (formatedIdMatrix,selectedClustalpath))-        else return (Left (show (fromLeft parsedClustalInput)))-    else do-      let clustalLines = T.lines clustalText-      let headerClustalTextLines = T.unlines (take 2 clustalLines)-      let headerlessClustalTextLines = T.unlines (drop 2 clustalLines)-      let reformatedClustalText = T.map reformatRNACodeAln headerlessClustalTextLines-      TI.writeFile selectedClustalpath (headerClustalTextLines `T.append` T.singleton '\n' `T.append` reformatedClustalText)-      return (Right ([],clustalFilepath))--formatIdMatrix :: Maybe (Int,Int,Double) -> String-formatIdMatrix (Just (_,_,c)) = printf "%.2f" c-formatIdMatrix _ = "-"----- | Sequence preselection for RNAz and RNAcode                   -rnaCodeSelectSeqs2 :: ClustalAlignment -> Int -> Double -> Double -> Bool -> (Matrix (Maybe (Int,Int,Double)),ClustalAlignment)-rnaCodeSelectSeqs2 currentClustalAlignment targetSeqNumber optimalIdentity maximalIdentity referenceSequence = (identityMatrix,newClustalAlignment)-  where entryVector = V.fromList (alignmentEntries currentClustalAlignment)-        entrySequences = V.map entryAlignedSequence entryVector-        entryReformatedSequences = V.map (T.map reformatRNACodeAln) entrySequences-        totalSeqNumber = V.length entryVector-        identityMatrix = computeSequenceIdentityMatrix entryReformatedSequences-        entryIdentityVector = V.map fromJust (V.filter isJust (getMatrixAsVector identityMatrix))-        entryIdentities = V.toList entryIdentityVector-        --Similarity filter - filter too similar sequences until alive seqs are less then minSeqs-        entriesToDiscard = preFilterIdentityMatrix maximalIdentity targetSeqNumber totalSeqNumber [] entryIdentities-        allEntries = [1..totalSeqNumber]-        prefilteredEntries = allEntries \\ entriesToDiscard-        --Optimize mean pairwise similarity (greedily) - remove worst sequence until desired number is reached-        costList = map (computeEntryCost optimalIdentity entryIdentityVector) prefilteredEntries-        sortedCostList = sortBy compareEntryCost2 costList-        sortedIndices = map fst sortedCostList-        --selectedEntryIndices = [1] ++ map fst (take (targetSeqNumber -1) sortedCostList)-        selectedEntryIndices = selectEntryIndices referenceSequence targetSeqNumber sortedIndices-        selectedEntries = map (\ind -> entryVector V.! (ind-1)) selectedEntryIndices-        selectedEntryHeader = map entrySequenceIdentifier selectedEntries-        reformatedSelectedEntryHeader =  map (T.map reformatRNACodeId) selectedEntryHeader-        selectedEntrySequences = map (\ind -> entryReformatedSequences V.! (ind-1)) selectedEntryIndices-        --gapfreeEntrySequences = T.transpose (T.filter (\a -> not (T.all isGap a)) (T.transpose selectedEntrySequences))-        gapfreeEntrySequences = T.transpose (filter (not . T.all isGap) (T.transpose selectedEntrySequences))-        gapfreeEntries = map (uncurry ClustalAlignmentEntry)(zip reformatedSelectedEntryHeader gapfreeEntrySequences)-        emptyConservationTrack = setEmptyConservationTrack gapfreeEntries (conservationTrack currentClustalAlignment)-        newClustalAlignment = currentClustalAlignment {alignmentEntries = gapfreeEntries, conservationTrack = emptyConservationTrack}--selectEntryIndices :: Bool -> Int -> [Int] -> [Int]-selectEntryIndices referenceSequence targetSeqNumber sortedIndices-  | referenceSequence = if (1 :: Int) `elem` firstX then firstX else 1:firstXm1-  | otherwise = firstX-    where firstXm1 = take (targetSeqNumber - 1)  sortedIndices-          firstX = take targetSeqNumber sortedIndices--setEmptyConservationTrack :: [ClustalAlignmentEntry] -> T.Text -> T.Text-setEmptyConservationTrack alnentries currentConservationTrack-  | null alnentries = currentConservationTrack-  | otherwise = newConservationTrack-      where trackLength = T.length (entryAlignedSequence (head alnentries))-            newConservationTrack = T.replicate (trackLength + 0) (T.pack " ")--isGap :: Char -> Bool-isGap a-  | a == '-' = True-  | otherwise = False--computeEntryCost :: Double -> V.Vector (Int,Int,Double) -> Int -> (Int,Double)-computeEntryCost optimalIdentity allIdentities currentIndex = (currentIndex,entryCost)-  where entryCost = V.sum (V.map (computeCost optimalIdentity) entryIdentities)-        entryIdentities = getEntryIdentities currentIndex allIdentities--getEntryIdentities :: Int -> V.Vector (Int,Int,Double) -> V.Vector (Int,Int,Double)-getEntryIdentities currentIndex allIdentities = V.filter (isIIdx currentIndex) allIdentities V.++ V.filter (isJIdx currentIndex) allIdentities--isIIdx :: Int -> (Int,Int,Double) -> Bool-isIIdx currentIdx (i,_,_) = currentIdx == i-isJIdx :: Int -> (Int,Int,Double) -> Bool-isJIdx currentIdx (_,j,_) = currentIdx == j--computeCost :: Double -> (Int,Int,Double) -> Double-computeCost optimalIdentity (_,_,c) = (c - optimalIdentity) * (c - optimalIdentity)--compareEntryCost2 :: (Int, Double) -> (Int, Double) -> Ordering-compareEntryCost2 (_,costA) (_,costB) = compare costA costB---- TODO change to vector-preFilterIdentityMatrix :: Double -> Int -> Int-> [Int] -> [(Int,Int,Double)] -> [Int]-preFilterIdentityMatrix identityCutoff minSeqNumber totalSeqNumber filteredIds entryIdentities-    | (totalSeqNumber - length filteredIds) <= minSeqNumber = []-    | identityCutoff == (100 :: Double) = []-    | Prelude.null entryIdentities  = []-    | otherwise = entryresult ++ preFilterIdentityMatrix identityCutoff minSeqNumber totalSeqNumber (filteredIds ++ entryresult) (tail entryIdentities)-      where currentEntry = head entryIdentities-            entryresult = checkIdentityEntry identityCutoff filteredIds currentEntry--checkIdentityEntry :: Double -> [Int] -> (Int,Int,Double) -> [Int]-checkIdentityEntry identityCutoff filteredIds (i,j,ident)-  | i `elem` filteredIds = []-  | j `elem` filteredIds = []-  | ident > identityCutoff = [j]-  | otherwise = []--computeSequenceIdentityMatrix :: V.Vector T.Text -> Matrix (Maybe (Int,Int,Double))-computeSequenceIdentityMatrix entryVector = matrix (V.length entryVector) (V.length entryVector) (computeSequenceIdentityEntry entryVector)---- Computes Sequence identity once for each pair and not vs itself-computeSequenceIdentityEntry :: V.Vector T.Text -> (Int,Int) -> Maybe (Int,Int,Double)-computeSequenceIdentityEntry entryVector (row,col)-  | i < j = Just (row,col,ident)-  | otherwise = Nothing-  where i=row-1-        j=col-1-        --gaps in both sequences need to be removed, because they count as match-        ientry  = entryVector V.! i-        jentry = entryVector V.! j-        (gfi,gfj) = unzip (filter notDoubleGap (T.zip ientry jentry))-        gfitext = T.pack gfi-        gfjtext = T.pack gfj-        --ident=stringIdentity gfi gfj-        ident=textIdentity gfitext gfjtext--notDoubleGap :: (Char,Char) -> Bool-notDoubleGap (a,b)-  | a == '-' && b == '-' = False-  | otherwise = True--reformatRNACodeId :: Char -> Char-reformatRNACodeId c-  | c == ':' = '-'-  | c == '|' = '-'-  | c == '.' = '-'-  | c == '~' = '-'-  | c == '_' = '-'-  | c == '/' = '-'-  | otherwise = c--reformatRNACodeAln :: Char -> Char-reformatRNACodeAln c-  | c == ':' = '-'-  | c == '|' = '-'-  | c == '.' = '-'-  | c == '~' = '-'-  | c == '_' = '-'-  | c == 'u' = 'U'-  | c == 't' = 'T'-  | c == 'g' = 'G'-  | c == 'c' = 'C'-  | c == 'a' = 'A'-  | otherwise = c--reformatAln :: Char -> Char-reformatAln c-  | c == '.' = '-'-  | c == '~' = '-'-  | c == '_' = '-'-  | c == 'u' = 'U'-  | c == 't' = 'T'-  | c == 'g' = 'G'-  | c == 'c' = 'C'-  | c == 'a' = 'A'-  | otherwise = c---- | Check if alien can connect to NCBI-checkNCBIConnection :: IO (Either String String)-checkNCBIConnection = do-   req <- N.parseRequest "https://www.ncbi.nlm.nih.gov"-   manager <- N.newManager N.tlsManagerSettings-   response <- N.httpLbs req manager-   let sta = N.responseStatus response-   if statusIsSuccessful sta-     then return (Right "Network connection with NCBI server was successful")-     else return (Left ("Could not connect to NCBI server \"https://www.ncbi.nlm.nih.gov\". Response Code: " ++ show (statusCode sta) ++ " \n" ++ B.unpack (statusMessage sta)))---- | Blast evalue is set stricter in inital alignment mode-setBlastExpectThreshold :: ModelConstruction -> Double-setBlastExpectThreshold modelConstruction-  | alignmentModeInfernal modelConstruction = 1 :: Double-  | otherwise = 0.1 :: Double--reformatFasta :: Sequence -> Sequence-reformatFasta input = Seq (seqheader input) updatedSequence Nothing-  where updatedSequence = SeqData (L.pack (map reformatFastaSequence (L.unpack (unSD (seqdata input)))))--reformatFastaSequence :: Char -> Char-reformatFastaSequence c-  | c == '.' = '-'-  | c == '~' = '-'-  | c == '_' = '-'-  | c == 'u' = 'T'-  | c == 't' = 'T'-  | c == 'g' = 'G'-  | c == 'c' = 'C'-  | c == 'a' = 'A'-  | c == 'U' = 'T'-  | otherwise = c--setRestrictedTaxonomyLimits :: String -> (Maybe Int,Maybe Int)-setRestrictedTaxonomyLimits trestriction-  | trestriction == "bacteria" = (Just (2 :: Int), Nothing)-  | trestriction == "archea" = (Just (2157 :: Int), Nothing)-  | trestriction == "eukaryia" = (Just (2759 :: Int), Nothing)-  | otherwise = (Nothing, Nothing)--checkTaxonomyRestriction :: Maybe String -> Maybe String-checkTaxonomyRestriction taxonomyRestriction-  | isJust taxonomyRestriction = checkTaxonomyRestrictionString (fromJust taxonomyRestriction)-  | otherwise = Nothing--checkTaxonomyRestrictionString :: String -> Maybe String-checkTaxonomyRestrictionString restrictionString-  | restrictionString == "archea" = Just "archea"-  | restrictionString == "bacteria" = Just "bacteria"-  | restrictionString == "eukaryia" = Just "eukaryia"-  | otherwise = Nothing--extractAlignmentSequencesByIds :: String -> [L.ByteString] -> IO [Sequence]-extractAlignmentSequencesByIds stockholmFilePath sequenceIds = do-  inputSeedAln <- TIO.readFile stockholmFilePath-  let alnEntries = extractAlignmentSequences inputSeedAln-  --let splitIds = map E.encodeUtf8 (TL.splitOn (TL.pack ",") (TL.pack sequenceIds))-  let filteredEntries = concatMap (filterSequencesById alnEntries) sequenceIds-  return filteredEntries--extractAlignmentSequences :: TL.Text -> [Sequence]-extractAlignmentSequences  seedFamilyAln = rfamIDAndseedFamilySequences-  where seedFamilyAlnLines = TL.lines seedFamilyAln-        -- remove empty lines from splitting-        seedFamilyNonEmpty =  filter (\alnline -> TL.empty /= alnline) seedFamilyAlnLines-        -- remove annotation and spacer lines-        seedFamilyIdSeqLines =  filter (\alnline -> not ((TL.head alnline) == '#') && not ((TL.head alnline) == ' ') && not ((TL.head alnline) == '/')) seedFamilyNonEmpty-        -- put id and corresponding seq of each line into a list and remove whitspaces        -        seedFamilyIdandSeqLines = map TL.words seedFamilyIdSeqLines-        -- linewise tuples with id and seq without alinment characters - .-        seedFamilyIdandSeqLineTuples = map (\alnline -> (head alnline,filterAlnChars (last alnline))) seedFamilyIdandSeqLines-        -- line tuples sorted by id-        seedFamilyIdandSeqTupleSorted = sortBy (\tuple1 tuple2 -> compare (fst tuple1) (fst tuple2)) seedFamilyIdandSeqLineTuples-        -- line tuples grouped by id-        seedFamilyIdandSeqTupleGroups = groupBy (\tuple1 tuple2 -> fst tuple1 == fst tuple2) seedFamilyIdandSeqTupleSorted-        seedFamilySequences = map mergeIdSeqTuplestoSequence seedFamilyIdandSeqTupleGroups-        rfamIDAndseedFamilySequences = seedFamilySequences--filterSequencesById :: [Sequence] -> L.ByteString -> [Sequence]-filterSequencesById alignmentSequences sequenceId = filter (sequenceHasId sequenceId) alignmentSequences--sequenceHasId :: L.ByteString -> Sequence -> Bool-sequenceHasId sequenceId currentSequence = sequenceId == unSL (seqid currentSequence)--filterAlnChars :: TL.Text -> TL.Text-filterAlnChars cs = TL.filter (\c -> not (c == '-') && not (c == '.')) cs--mergeIdSeqTuplestoSequence :: [(TL.Text,TL.Text)] -> Sequence-mergeIdSeqTuplestoSequence tuplelist = currentSequence-  where seqId = fst (head tuplelist)-        seqData = TL.concat (map snd tuplelist)-        currentSequence = Seq (SeqLabel (E.encodeUtf8 seqId)) (SeqData (E.encodeUtf8 seqData)) Nothing-
− src/Bio/RNAlienStatistics.hs
@@ -1,331 +0,0 @@-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE DeriveDataTypeable #-}---- | Statistics for RNAlien Results--- dist/build/RNAlienStatistics/RNAlienStatistics -s bitscore -i /scratch/egg/temp/cm13676/1/model.cm -r /home/mescalin/egg/current/Data/AlienTest/cms/BsrG.cm -g /scratch/egg/temp/AlienSearch/genomes/ -o /scratch/egg/temp/AlienStatistics-module Main where--import System.Console.CmdArgs-import Data.Either.Unwrap-import System.Process-import qualified Data.ByteString.Lazy.Char8 as L-import Bio.RNAlienLibrary-import System.Directory-import Bio.Core.Sequence-import Bio.Sequence.Fasta-import Data.List-import qualified System.FilePath as FP-import qualified Data.List.Split as DS-import Text.Printf-import Bio.RNAzParser-import qualified Bio.RNAcodeParser as RC--data Options = Options-  { alienCovarianceModelPath  :: String,-    alienrnazPath :: String,-    alienrnacodePath :: String,-    aliencmstatPath :: String,-    rfamCovarianceModelPath :: String,-    rfamFastaFilePath :: String,-    alienFastaFilePath :: String,-    rfamModelName :: String,-    rfamModelId :: String,-    rfamThreshold :: Double,-    alienThreshold :: Double,-    databaseSize :: Maybe Double,-    outputDirectoryPath :: String,-    benchmarkIndex :: Int,-    thresholdSelection :: String,-    linkScores :: Bool,-    threads :: Int-  } deriving (Show,Data,Typeable)--options :: Options-options = Options-  { alienCovarianceModelPath = def &= name "i" &= help "Path to alienCovarianceModelPath",-    alienrnazPath = def &= name "z" &= help "Path to alienRNAzResult",-    alienrnacodePath = def &= name "w" &= help "Path to alienRNAcodeResult",-    aliencmstatPath = def &= name "m" &= help "Path to aliencmstatResult",-    rfamCovarianceModelPath = def &= name "r" &= help "Path to rfamCovarianceModelPath",-    rfamFastaFilePath = def &= name "g" &= help "Path to rfamFastaFile",-    rfamModelName = def &= name "n" &= help "Rfam model name",-    rfamModelId = def &= name "d" &= help "Rfam model id",-    alienFastaFilePath = def &= name "a" &= help "Path to alienFastaFile",-    outputDirectoryPath = def &= name "o" &= help "Path to output directory",-    alienThreshold = 20 &= name "t" &= help "Bitscore threshold for RNAlien model hits on Rfam fasta, default 20",-    rfamThreshold = 20 &= name "x" &= help "Bitscore threshold for Rfam model hits on Alien fasta, default 20",-    databaseSize = Nothing  &= name "k" &= help "Cmsearch database size in mega bases. default not set",-    benchmarkIndex = 1 &= name "b" &= help "Index used to identify sRNA tagged RNA families",-    thresholdSelection = "bitscore" &= name "s" &= help "Selection method, (bitscore, evalue), default bitscore",-    linkScores = False &= name "l" &= help "Triggers computation of linkscores via CMCompare",-    threads = 1 &= name "c" &= help "Number of available cpu slots/cores, default 1"-  } &= summary "RNAlienStatistics" &= help "Florian Eggenhofer - >2013" &= verbosity----cmSearchFasta threads rfamCovarianceModelPath outputDirectoryPath "Rfam" False genomesDirectoryPath-cmSearchFasta :: Int -> String -> Double -> Maybe Double -> Int -> String -> String -> String -> String -> IO [CMsearchHit]-cmSearchFasta benchmarkIndex thresholdSelection thresholdScore databaseSize cpuThreads covarianceModelPath outputDirectory modelType fastapath = do-  createDirectoryIfMissing False (outputDirectory ++ "/" ++ modelType)-  _ <- systemCMsearch cpuThreads (maybe "" (\dbs -> " -Z " ++ show dbs ++ " ") databaseSize)  covarianceModelPath fastapath (outputDirectory ++ "/" ++ modelType ++ "/" ++ show benchmarkIndex ++ ".cmsearch")-  --_ <- systemCMsearch cpuThreads " " covarianceModelPath fastapath (outputDirectory ++ "/" ++ modelType ++ "/" ++ (show benchmarkIndex) ++ ".cmsearch")-  result <- readCMSearch (outputDirectory ++ "/" ++ modelType ++ "/" ++ show benchmarkIndex ++ ".cmsearch")-  if isLeft result-     then do-       print (fromLeft result)-       return []-     else do-       let rightResults = fromRight result-       let significantHits = filterCMsearchHits thresholdSelection thresholdScore rightResults-       let uniquesignificantHits = nubBy cmSearchSameHit significantHits-       return uniquesignificantHits----cmSearchFasta threads rfamCovarianceModelPath outputDirectoryPath "Rfam" False genomesDirectoryPath-cmSearchesFasta :: Int -> String -> Double -> Maybe Double -> Int -> String -> String -> String -> String -> IO [CMsearchHit]-cmSearchesFasta benchmarkIndex thresholdSelection thresholdScore databaseSize cpuThreads covarianceModelPath outputDirectory modelType fastapath = do-  createDirectoryIfMissing False (outputDirectory ++ "/" ++ modelType)-  _ <- systemCMsearch cpuThreads (maybe "" (\dbs -> " -Z " ++ show dbs ++ " ") databaseSize) covarianceModelPath fastapath (outputDirectory ++ "/" ++ modelType ++ "/" ++ show benchmarkIndex ++ ".cmsearch")-  --_ <- systemCMsearch cpuThreads " " covarianceModelPath fastapath (outputDirectory ++ "/" ++ modelType ++ "/" ++ (show benchmarkIndex) ++ ".cmsearch")-  result <- readCMSearches (outputDirectory ++ "/" ++ modelType ++ "/" ++ show benchmarkIndex ++ ".cmsearch")-  if isLeft result-     then do-       print (fromLeft result)-       return []-     else do-       let rightResults = fromRight result-       let significantHits = filterCMsearchHits thresholdSelection thresholdScore rightResults-       --putStrLn ("significant Hits " ++ show (length significantHits))-       let uniquesignificantHits = nubBy cmSearchSameHit significantHits-       --putStrLn ("unique significant Hits " ++ show (length uniquesignificantHits))-       --let organismUniquesignificantHits = nubBy cmSearchSameOrganism significantHits-       return uniquesignificantHits--filterCMsearchHits :: String -> Double -> CMsearch -> [CMsearchHit]-filterCMsearchHits thresholdSelection thresholdScore cmSearchResult-  | thresholdSelection == "bitscore" = bitscorefiltered-  | otherwise =  evaluefiltered-  where bitscorefiltered = filter (\hit -> hitScore hit >= thresholdScore) (cmsearchHits cmSearchResult)-        evaluefiltered = filter (\hit -> hitEvalue hit <= thresholdScore) (cmsearchHits cmSearchResult)--partitionCMsearchHits :: String -> Double -> CMsearch -> ([CMsearchHit],[CMsearchHit])-partitionCMsearchHits thresholdSelection thresholdScore cmSearchResult-  | thresholdSelection == "bitscore" = (bitscoreselected,bitscorerejected)-  | otherwise =  (evalueselected,evaluerejected)-  where (bitscoreselected,bitscorerejected) = partition (\hit -> hitScore hit >= thresholdScore) (cmsearchHits cmSearchResult)-        (evalueselected,evaluerejected) = partition (\hit -> hitEvalue hit <= thresholdScore) (cmsearchHits cmSearchResult)--trimCMsearchFastaFile :: String -> String -> String -> CMsearch -> String -> IO ()-trimCMsearchFastaFile genomesDirectory outputFolder modelType cmsearch fastafile  = do-  let fastaInputPath = genomesDirectory ++ "/" ++ fastafile-  let fastaOutputPath = outputFolder ++ "/" ++ modelType ++ "/" ++ fastafile-  fastaSequences <- readFasta fastaInputPath-  let trimmedSequence = trimCMsearchSequence cmsearch (head fastaSequences)-  writeFasta fastaOutputPath [trimmedSequence]--trimCMsearchSequence :: CMsearch -> Sequence -> Sequence-trimCMsearchSequence cmSearchResult inputSequence = subSequence-  where hitScoreEntry = head (cmsearchHits cmSearchResult)-        sequenceString = L.unpack (unSD (seqdata inputSequence))-        sequenceSubstring = cmSearchsubString (hitStart hitScoreEntry) (hitEnd hitScoreEntry) sequenceString-        newSequenceHeader =  L.pack (L.unpack (unSL (seqheader inputSequence)) ++ "cmS_" ++ show (hitStart hitScoreEntry) ++ "_" ++ show (hitEnd hitScoreEntry) ++ "_" ++ show (hitStrand hitScoreEntry))-        subSequence = Seq (SeqLabel newSequenceHeader) (SeqData (L.pack sequenceSubstring)) Nothing----With paralogs allowed-cmSearchSameHit :: CMsearchHit -> CMsearchHit -> Bool-cmSearchSameHit hitscore1 hitscore2-  | unpackedSeqHeader1 == unpackedSeqHeader2 = True-  | otherwise = False-  where unpackedSeqHeader1 = L.unpack (hitSequenceHeader hitscore1)-        unpackedSeqHeader2 = L.unpack (hitSequenceHeader hitscore2)--cmSearchSameOrganism :: CMsearchHit -> CMsearchHit -> Bool-cmSearchSameOrganism hitscore1 hitscore2-  | hitOrganism1 == hitOrganism2 = True-  | otherwise = False-  where unpackedSeqHeader1 = L.unpack (hitSequenceHeader hitscore1)-        unpackedSeqHeader2 = L.unpack (hitSequenceHeader hitscore2)-        separationcharacter1 = selectSeparationChar unpackedSeqHeader1-        separationcharacter2 = selectSeparationChar unpackedSeqHeader2-        hitOrganism1 = head (DS.splitOn separationcharacter1 unpackedSeqHeader1)-        hitOrganism2 = head (DS.splitOn separationcharacter2 unpackedSeqHeader2)--selectSeparationChar :: String -> String-selectSeparationChar inputString-  | any ((== ':')) inputString = ":"-  | otherwise = "/"--main :: IO ()-main = do-  Options{..} <- cmdArgs options-  rfamModelExists <- doesFileExist rfamCovarianceModelPath-  verbose <- getVerbosity-  rnazString <- rnazOutput verbose alienrnazPath-  rnacodeString <- rnaCodeOutput verbose alienrnacodePath-  cmStatString <- cmStatOutput verbose aliencmstatPath-  if rfamModelExists-    then do-      --compute linkscore-      linkscore <- if linkScores-        then compareCM rfamCovarianceModelPath alienCovarianceModelPath outputDirectoryPath-        else return (Left "-")-      rfamMaxLinkScore <- if linkScores then compareCM rfamCovarianceModelPath rfamCovarianceModelPath outputDirectoryPath else return (Left "-")-      alienMaxLinkscore <- if linkScores then compareCM alienCovarianceModelPath alienCovarianceModelPath outputDirectoryPath else return (Left "-")-      _ <- system ("cat " ++ rfamFastaFilePath ++ " | grep '>' | wc -l >" ++ outputDirectoryPath ++ FP.takeFileName rfamFastaFilePath ++ ".entries")-      _ <- system ("cat " ++ alienFastaFilePath ++ " | grep '>' | wc -l >" ++ outputDirectoryPath ++ FP.takeFileName alienFastaFilePath ++ ".entries")-      rfamFastaEntries <- readFile (outputDirectoryPath ++ FP.takeFileName rfamFastaFilePath ++ ".entries")-      alienFastaEntries <- readFile (outputDirectoryPath ++ FP.takeFileName alienFastaFilePath ++ ".entries")-      let rfamFastaEntriesNumber = read rfamFastaEntries :: Int-      let alienFastaEntriesNumber = read alienFastaEntries :: Int-      rfamonAlienResults <- cmSearchesFasta benchmarkIndex thresholdSelection rfamThreshold databaseSize threads rfamCovarianceModelPath outputDirectoryPath "rfamOnAlien" alienFastaFilePath-      alienonRfamResults <- cmSearchFasta benchmarkIndex thresholdSelection alienThreshold databaseSize threads alienCovarianceModelPath outputDirectoryPath "alienOnRfam" rfamFastaFilePath-      let rfamonAlienResultsNumber = length rfamonAlienResults-      let alienonRfamResultsNumber = length alienonRfamResults-      let rfamonAlienRecovery = (fromIntegral rfamonAlienResultsNumber :: Double) / (fromIntegral alienFastaEntriesNumber :: Double)-      let alienonRfamRecovery = (fromIntegral alienonRfamResultsNumber :: Double) / (fromIntegral rfamFastaEntriesNumber :: Double)-      if verbose == Loud-        then do-          putStrLn ("BenchmarkIndex: " ++ show benchmarkIndex)-          putStrLn ("RfamModelName: " ++ rfamModelName)-          putStrLn ("RfamModelId: " ++ rfamModelId)-          putStrLn ("Linkscore: " ++ either id show linkscore)-          putStrLn ("rfamMaxLinkScore: " ++ either id show rfamMaxLinkScore)-          putStrLn ("alienMaxLinkscore: " ++ either id show alienMaxLinkscore)-          putStrLn ("rfamGatheringThreshold: " ++ show rfamThreshold)-          putStrLn ("alienGatheringThreshold: " ++ show alienThreshold)-          putStrLn ("rfamFastaEntriesNumber: " ++ show rfamFastaEntriesNumber)-          putStrLn ("alienFastaEntriesNumber: " ++ show alienFastaEntriesNumber)-          putStrLn ("rfamonAlienResultsNumber: " ++ show rfamonAlienResultsNumber)-          putStrLn ("alienonRfamResultsNumber: " ++ show alienonRfamResultsNumber)-          putStrLn ("RfamonAlienRecovery: " ++ show rfamonAlienRecovery)-          putStrLn ("AlienonRfamRecovery: " ++ show alienonRfamRecovery)-          print rnazString-          print rnacodeString-          print cmStatString-        else-          putStrLn (show benchmarkIndex ++ "\t" ++ rfamModelName ++ "\t" ++ rfamModelId ++ "\t" ++  (either id show linkscore) ++ "\t" ++  (either id show rfamMaxLinkScore) ++ "\t" ++ (either id show alienMaxLinkscore) ++ "\t" ++ show rfamThreshold ++ "\t" ++ show alienThreshold ++ "\t" ++ show rfamFastaEntriesNumber ++ "\t" ++ show alienFastaEntriesNumber ++ "\t" ++ show rfamonAlienResultsNumber ++ "\t" ++ show alienonRfamResultsNumber ++ "\t" ++ printf "%.2f" rfamonAlienRecovery  ++ "\t" ++ printf "%.2f" alienonRfamRecovery ++ "\t" ++ rnazString ++ "\t" ++ rnacodeString ++ "\t" ++ cmStatString)-    else do-      --compute linkscore-      alienMaxLinkscore <- if linkScores then compareCM alienCovarianceModelPath alienCovarianceModelPath outputDirectoryPath else return ( Left "-")-      _ <- system ("cat " ++ alienFastaFilePath ++ " | grep '>' | wc -l >" ++ outputDirectoryPath ++ FP.takeFileName alienFastaFilePath ++ ".entries")-      alienFastaEntries <- readFile (outputDirectoryPath ++ FP.takeFileName alienFastaFilePath ++ ".entries")-      let alienFastaEntriesNumber = read alienFastaEntries :: Int-      if verbose == Loud-        then do-          putStrLn "BenchmarkIndex:"-          putStrLn "RfamModelName: -"-          putStrLn "RfamModelId: -"-          putStrLn "Linkscore: -"-          putStrLn "rfamMaxLinkScore: -"-          putStrLn ("alienMaxLinkscore: " ++  either id show alienMaxLinkscore)-          putStrLn "rfamGatheringThreshold: -"-          putStrLn "alienGatheringThreshold: -"-          putStrLn "rfamFastaEntriesNumber: -"-          putStrLn ("alienFastaEntriesNumber: " ++ show alienFastaEntriesNumber)-          putStrLn "rfamonAlienResultsNumber: -"-          putStrLn "alienonRfamResultsNumber: -"-          putStrLn "RfamonAlienRecovery: -"-          putStrLn "AlienonRfamRecovery: -"-          print rnazString-          print cmStatString-        else-          putStrLn (show benchmarkIndex ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ (either id show alienMaxLinkscore) ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ show alienFastaEntriesNumber ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-"  ++ "\t" ++ "-" ++ "\t" ++ rnazString  ++ "\t" ++ rnacodeString ++ "\t" ++ cmStatString)--rnazOutput :: Verbosity -> String -> IO String-rnazOutput verbose rnazPath = do-  rnazPresent <- doesFileExist rnazPath-  if rnazPresent-    then do-      inputRNAz <- readRNAz rnazPath-      if isRight inputRNAz-        then do-          let rnaZ = fromRight inputRNAz-          if verbose == Loud-            then do-              let output = "Mean pairwise identity: " ++ show (meanPairwiseIdentity rnaZ) ++ "\n  Shannon entropy: " ++ show (shannonEntropy rnaZ) ++  "\n  GC content: " ++ show (gcContent rnaZ) ++ "\n  Mean single sequence minimum free energy: " ++ show (meanSingleSequenceMinimumFreeEnergy rnaZ) ++ "\n  Consensus minimum free energy: " ++ show (consensusMinimumFreeEnergy rnaZ) ++ "\n  Energy contribution: " ++ show (energyContribution rnaZ) ++ "\n  Covariance contribution: " ++ show (covarianceContribution rnaZ) ++ "\n  Combinations pair: " ++ show (combinationsPair rnaZ) ++ "\n  Mean z-score: " ++ show (meanZScore rnaZ) ++ "\n  Structure conservation index: " ++ show (structureConservationIndex rnaZ) ++ "\n  Background model: " ++ backgroundModel rnaZ ++ "\n  Decision model: " ++ decisionModel rnaZ ++ "\n  SVM decision value: " ++ show (svmDecisionValue rnaZ) ++ "\n  SVM class propability: " ++ show (svmRNAClassProbability rnaZ) ++ "\n  Prediction: " ++ prediction rnaZ-              return output-            else do-              let output = show (meanPairwiseIdentity rnaZ) ++ "\t" ++ show (shannonEntropy rnaZ) ++  "\t" ++ show (gcContent rnaZ) ++ "\t" ++ show (meanSingleSequenceMinimumFreeEnergy rnaZ) ++ "\t" ++ show (consensusMinimumFreeEnergy rnaZ) ++ "\t" ++ show (energyContribution rnaZ) ++ "\t" ++ show (covarianceContribution rnaZ) ++ "\t" ++ show (combinationsPair rnaZ) ++ "\t" ++ show (meanZScore rnaZ) ++ "\t" ++ show (structureConservationIndex rnaZ) ++ "\t" ++ show (svmDecisionValue rnaZ) ++ "\t" ++ show (svmRNAClassProbability rnaZ) ++ "\t" ++ prediction rnaZ-              return output-         else-           if (verbose == Loud)-            then do-              let output = "Mean pairwise identity: " ++ " - \n  Shannon entropy: " ++ " - \n  GC content: " ++ " - \n  Mean single sequence minimum free energy: " ++ " - \n  Consensus minimum free energy: " ++ " - \n  Energy contribution: " ++ " - \n  Covariance contribution: " ++ " - \n  Combinations pair: " ++ " - \n  Mean z-score: " ++ " - \n  Structure conservation index: " ++ " - \n  Background model: " ++ " - \n  Decision model: " ++ " - \n  SVM decision value: " ++ " - \n  SVM class propability: " ++ " - \n  Prediction: " ++ " - \n"-              return output-            else do-              let output = "-" ++ "\t" ++ "-" ++  "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-"-              return output-    else-       if (verbose == Loud)-         then do-           let output = "Mean pairwise identity: " ++ " - \n  Shannon entropy: " ++ " - \n  GC content: " ++ " - \n  Mean single sequence minimum free energy: " ++ " - \n  Consensus minimum free energy: " ++ " - \n  Energy contribution: " ++ " - \n  Covariance contribution: " ++ " - \n  Combinations pair: " ++ " - \n  Mean z-score: " ++ " - \n  Structure conservation index: " ++ " - \n  Background model: " ++ " - \n  Decision model: " ++ " - \n  SVM decision value: " ++ " - \n  SVM class propability: " ++ " - \n  Prediction: " ++ " - \n"-           return output-         else do-           let output = "-" ++ "\t" ++ "-" ++  "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-" ++ "\t" ++ "-"-           return output--cmStatOutput :: Verbosity -> String -> IO String-cmStatOutput verbose cmstatPath = do-  cmstatPresent <- doesFileExist cmstatPath-  if cmstatPresent-    then do-      inputCMstat <- readCMstat cmstatPath-      if isRight inputCMstat-        then do-          let cmStat = fromRight inputCMstat-          if verbose == Loud-            then do-              let output = "statSequenceNumber: " ++ show (statSequenceNumber cmStat) ++ "\nstatEffectiveSequences: " ++ show (statEffectiveSequences cmStat) ++ "\nstatConsensusLength: " ++ show (statConsensusLength cmStat) ++ "\nstatW: " ++ show (statW cmStat) ++ "\nstatBasepairs: " ++ show (statBasepairs cmStat) ++ "\nstatBifurcations: " ++ show (statBifurcations cmStat) ++ "\nstatModel: " ++ statModel cmStat ++ "\nrelativeEntropyCM: " ++ show (relativeEntropyCM cmStat) ++ "\nrelativeEntropyHMM: " ++ show (relativeEntropyHMM cmStat)-              return output-            else do-              let output = show (statSequenceNumber cmStat) ++ "\t" ++ show (statEffectiveSequences cmStat) ++ "\t" ++ show (statConsensusLength cmStat) ++ "\t" ++ show (statW cmStat) ++ "\t" ++ show (statBasepairs cmStat) ++ "\t" ++ show (statBifurcations cmStat) ++ "\t" ++ statModel cmStat ++ "\t" ++ show (relativeEntropyCM cmStat) ++ "\t" ++ show (relativeEntropyHMM cmStat)-              return output-         else-           if (verbose == Loud)-            then do-              let output = "statSequenceNumber: -" ++ "\nstatEffectiveSequences: -" ++ "\nstatConsensusLength: -" ++ "\nstatW: -" ++ "\nstatBasepairs: -" ++ "\nstatBifurcations: -" ++ "\nstatModel: -" ++ "\nrelativeEntropyCM: -" ++ "\nrelativeEntropyHMM: -"-              return output-            else do-              let output = "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-"-              return output-    else-       if (verbose == Loud)-         then do-           let output = "statSequenceNumber: -" ++ "\nstatEffectiveSequences: -" ++ "\nstatConsensusLength: -" ++ "\nstatW: -" ++ "\nstatBasepairs: -" ++ "\nstatBifurcations: -" ++ "\nstatModel: -" ++ "\nrelativeEntropyCM: -" ++ "\nrelativeEntropyHMM: -"-           return output-         else do-           let output = "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-\t" ++ "-"-           return output--rnaCodeOutput :: Verbosity -> String -> IO String-rnaCodeOutput verbose rnaCodePath = do-  rnacodePresent <- doesFileExist rnaCodePath-  if rnacodePresent-    then do-      inputRNACode <- RC.readRNAcodeTabular rnaCodePath-      if isRight inputRNACode-        then do-          let rnaCode = fromRight inputRNACode-          let lowestPvalue = minimum (map RC.pvalue (RC.rnacodeHits rnaCode))-          let rnaCodeClassification = if lowestPvalue < 0.05 then "PROTEIN" else "OTHER"-          if verbose == Loud-            then do-              let output = "RNAcode lowest p-value: " ++ show lowestPvalue ++ "\nrnaCodeClassification: " ++ rnaCodeClassification-              return output-            else do-              let output = show lowestPvalue ++ "\t" ++ rnaCodeClassification-              return output-         else-           if (verbose == Loud)-            then do-              let output = "RNAcode lowest p-value: " ++ "-" ++ "\nrnaCodeClassification: " ++ "-"-              return output-            else do-              let output = "-\t" ++ "-"-              --let output = show (fromLeft inputRNACode)-              return output-    else-       if (verbose == Loud)-         then do-           let output =  "RNAcode lowest p-value: " ++ "-" ++ "\nrnaCodeClassification: " ++ "-"-           return output-         else do-           let output = "-\t" ++ "-"-           return output
− src/Bio/cmsearchToBED.hs
@@ -1,178 +0,0 @@-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE DeriveDataTypeable #-}---- | Convert cmsearch output to Browser Extensible Data (BED) format---   Testcommand: cmsearchToBED -i /path/to/test.clustal-module Main where-import Prelude-import System.Console.CmdArgs-import Bio.RNAlienLibrary-import Data.Either.Unwrap-import qualified Data.ByteString.Lazy.Char8 as L-import qualified Data.Text as T-import Data.List--data Bed = Bed-  { browserPostition :: T.Text,-    browserSettings :: T.Text,-    bedName :: T.Text,-    bedDescription :: T.Text,-    bedVisibility :: Int,-    bedItemRgb :: Bool,-    bedEntries :: [BedEntry]-  } deriving (Eq, Read)--instance Show Bed where-  show (Bed _browserPostition _browserSettings _bedName _bedDescription _bedVisibility _bedItemRgb _bedEntries) = a ++ b ++ c ++ d ++ e ++ f ++ g-    where a = "browser position " ++ T.unpack _browserPostition ++ "\n"-          b = T.unpack _browserSettings ++ "\n"-          c = "track name=\"" ++ T.unpack _bedName  ++ "\" "-          d = "description=\"" ++ T.unpack _bedDescription ++ "\" "-          e = "visibility=" ++  show _bedVisibility ++ " "-          f = "itemRgb=\"" ++ itemRbg ++ "\"\n"-          itemRbg = if _bedItemRgb then "On" else "Off"-          g = concatMap show _bedEntries---data BedEntry = BedEntry-  { chrom :: T.Text,-    chromStart :: Int,-    chromEnd  :: Int,-    chromName :: Maybe T.Text,-    score :: Maybe Int,-    strand :: Maybe Char,-    thickStart :: Maybe Int,-    thickEnd :: Maybe Int,-    color :: Maybe T.Text,-    blockCount :: Maybe Int,-    blockSizes :: Maybe [Int],-    blockStarts :: Maybe [Int]-  } deriving (Eq, Read)--instance Show BedEntry where-  show (BedEntry _chrom _chromStart _chromEnd _chromName _score _strand _thickStart _thickEnd _color _blockCount _blockSizes _blockStarts) = a ++ b ++ c ++ d ++ e ++ f ++ g ++ h ++ i ++ j ++ k ++ l-    where a = T.unpack _chrom ++ "\t"-          b = show _chromStart ++ "\t"-          c = show _chromEnd ++ "\t"-          d = maybe "" T.unpack _chromName ++ "\t"-          e = maybe "" show _score ++ "\t"-          f = maybe "" ((: []))  _strand ++ "\t"-          g = maybe "" show _thickStart ++ "\t"-          h = maybe "" show _thickEnd ++ "\t"-          i = maybe "" T.unpack _color ++ "\t"-          j = maybe "" show _blockCount ++ "\t"-          k = maybe "" (intercalate "," . map show) _blockSizes ++ "\t"-          l = maybe "" (intercalate "," . map show) _blockStarts ++ "\n"--data Options = Options-  { cmsearchPath :: String,-    inputBrowserSettings :: String,-    inputBedVisibility :: Int,-    inputTrackName :: String,-    inputTrackDescription :: String,-    inputItemRgb :: Bool,-    inputTrackColor :: String,-    sortBed :: Bool,-    withHeader :: Bool-  } deriving (Show,Data,Typeable)--options :: Options-options = Options-  { cmsearchPath = def &= name "i" &= help "Path to input cmsearch file",-    inputBrowserSettings = "browser hide all" &= name "b" &= help "Browser settings. Default: browser hide all",-    inputBedVisibility = (2 :: Int) &= name "y" &= help "Visibility setting of track. Default: 2",-    inputTrackName = "PredictedRNA" &= name "n" &= help "Name of the track Default: PredictedRNA",-    inputTrackDescription = "RNA loci predicted by cmsearch" &= name "d" &= help "Description of the track. Default: RNA loci predicted by cmsearch",-    inputItemRgb = True &= name "r" &= help "RGB Color of the track. Default: True",-    inputTrackColor = "255,0,0" &= name "c" &= help "RGB Color of the track. Default: 255,0,0",-    sortBed = True &= name "s" &= help "Sort entries of Bed file by start end end cooridinates. Default: True",-    withHeader = True &= name "w" &= help "Output contains bed header. Default: True"-  } &= summary "cmsearchToBED - Converts cmsearch file hits to BED file entries" &= help "Florian Eggenhofer 2016" &= verbosity--main :: IO ()-main = do-  Options{..} <- cmdArgs options-  parsedCmsearch <- readCMSearch cmsearchPath-  if isRight parsedCmsearch-     then do-       let outputBED = convertcmSearchToBED (fromRight parsedCmsearch) inputBrowserSettings inputTrackName inputTrackDescription inputTrackColor inputBedVisibility inputItemRgb sortBed-       if isRight outputBED-         then-           if withHeader-             then print (fromRight outputBED)-             else do-               let output = concatMap show (bedEntries (fromRight outputBED))-               putStr output-         else putStr (fromLeft outputBED)-     else putStr ("A problem occured converting from cmsearch to BED format:\n " ++ show (fromLeft parsedCmsearch))----convertcmSearchToBED :: CMsearch -> String -> String -> Either String String---convertcmSearchToBED inputcmsearch trackName trackColor---  | null cmHits = Left "cmsearch file contains no hits" ---  | otherwise = Right (bedHeader ++ bedEntries)---  where cmHits = cmsearchHits inputcmsearch---        bedHeader = "browser position " ++ browserPosition ++ "\nbrowser hide all\ntrack name=\"cmsearch hits\" description=\"cmsearch hits\" visibility=2 itemRgb=\"On\"\n"---        bedEntries = concatMap (cmsearchHitToBEDentry trackName trackColor) cmHits---        browserPosition = L.unpack (hitSequenceHeader firstHit) ++ ":" ++ entryStart firstHit ++ "-" ++ entryEnd firstHit---        firstHit = (head cmHits)        --convertcmSearchToBED :: CMsearch -> String -> String -> String -> String -> Int -> Bool -> Bool -> Either String Bed-convertcmSearchToBED inputcmsearch inputBrowserSettings trackName trackDescription trackColor inputBedVisibility inputItemRgb sortBed-  | null cmHits = Left "cmsearch file contains no hits"-  | otherwise = Right bed-  where cmHits = cmsearchHits inputcmsearch-        --bedHeader = "browser position " ++ browserPosition ++ "\nbrowser hide all\ntrack name=\"cmsearch hits\" description=\"cmsearch hits\" visibility=2 itemRgb=\"On\"\n"-        bedEntries = map (cmsearchHitToBEDentry trackName trackColor) cmHits-        sortedBedEntries = if sortBed then sortBy orderBedEntry bedEntries else bedEntries-        currentBrowserPosition = T.unpack (chrom firstEntry) ++ ":" ++ show (chromStart firstEntry) ++ "-" ++ show (chromEnd firstEntry)-        firstEntry = head sortedBedEntries-        bed = Bed (T.pack currentBrowserPosition) (T.pack inputBrowserSettings) (T.pack trackName) (T.pack trackDescription) inputBedVisibility inputItemRgb sortedBedEntries--cmsearchHitToBEDentry :: String -> String -> CMsearchHit -> BedEntry-cmsearchHitToBEDentry hitName hitColor cmHit = entry-  where entry = BedEntry  chromosome entrystart entryend (Just (T.pack hitName)) entryscore entrystrand thickstart thickend entrycolor blocks blockSize blockStart-        chromosome = T.pack (L.unpack (hitSequenceHeader cmHit))-        --entryline = L.unpack (hitSequenceHeader cmHit) ++ "\t" ++ entryStart cmHit ++ "\t" ++ entryEnd cmHit++ "\t" ++ (hitName) ++ "\t" ++ "0" ++ "\t" ++ [(hitStrand cmHit)] ++ "\t" ++ show (hitStart cmHit) ++ "\t" ++ show (hitEnd cmHit) ++ "\t" ++ hitColor ++ "\n"-        entrystart = if hitStrand cmHit == '+' then hitStart cmHit else hitEnd cmHit-        entryend = if hitStrand cmHit == '+' then hitEnd cmHit else hitStart cmHit-        entryscore = Just (0 :: Int)-        entrystrand = Just (hitStrand cmHit)-        thickstart = Just entrystart-        thickend = Just entryend-        entrycolor = Just (T.pack hitColor)-        blocks = Just (1 :: Int)-        blockSize = Just [entryend - entrystart]-        blockStart = Just [0 :: Int]-----cmsearchHitToBEDentry :: String -> String -> CMsearchHit -> String---cmsearchHitToBEDentry hitName hitColor cmHit = entryline---  where entryline = L.unpack (hitSequenceHeader cmHit) ++ "\t" ++ entryStart cmHit ++ "\t" ++ entryEnd cmHit++ "\t" ++ (hitName) ++ "\t" ++ "0" ++ "\t" ++ [(hitStrand cmHit)] ++ "\t" ++ show (hitStart cmHit) ++ "\t" ++ show (hitEnd cmHit) ++ "\t" ++ hitColor ++ "\n"-        --entrystart = if (hitStrand cmHit) == '+' then show (hitStart cmHit) else show (hitEnd cmHit)-        --entryend = if (hitStrand cmHit) == '+' then show (hitEnd cmHit) else show (hitStart cmHit)--entryStart :: CMsearchHit -> String-entryStart cmHit-  | hitStrand cmHit == '+' = show (hitStart cmHit)-  | otherwise = show (hitEnd cmHit)--entryEnd :: CMsearchHit -> String-entryEnd cmHit-  | hitStrand cmHit == '+' = show (hitEnd cmHit)-  | otherwise = show (hitStart cmHit)--orderBedEntry :: BedEntry -> BedEntry -> Ordering-orderBedEntry firstHit secondHit-  | start1 > start2 = GT-  | start1 < start2 = LT-  | otherwise = orderBedEntryEnd firstHit secondHit-    where start1 = chromStart firstHit-          start2 = chromStart secondHit--orderBedEntryEnd :: BedEntry -> BedEntry -> Ordering-orderBedEntryEnd firstHit secondHit-  | end1 > end2 = GT-  | end1 < end2 = LT-  | otherwise = EQ-    where end1 = chromEnd firstHit-          end2 = chromEnd secondHit