packages feed

Forestry-0.0.0.1: src/RNAforestry.hs

{-# Options_GHC -fno-cse #-}

module Main where

import           Control.Lens
import           Data.ByteString.Lens
import           Control.Monad (void, when)
import           Data.Function ((&))
import qualified Data.Attoparsec.ByteString.Streaming as A
import qualified Data.ByteString.Streaming.Char8 as Q
import qualified Streaming as S
import qualified Streaming.Prelude as SP
import           System.Console.CmdArgs
import           System.Exit (exitSuccess, exitFailure)
import qualified Data.Vector as V
import           Numeric.Log

import           Biobase.Newick.Types
import           Biobase.Secondary.New (parseVienna, toTree, _label)
import           Biobase.Types.Structure
import           BioInf.ViennaRNA.RNAfold as RNAfold
import           Data.Forest.Static
import qualified Diagrams.TwoD.ProbabilityGrid as PG

import qualified Data.Forest.Static.Align.Affine as AA
import qualified Data.Forest.Static.Align.Linear as AL



-- | Which options do we provide.

data Options
  = AlignLinear
    { smatch        ∷ Int
    , smismatch     ∷ Int
    , sindel        ∷ Int
    , probabilities ∷ Bool
    , fillweight    ∷ PG.FillWeight
    , temperature   ∷ Double
    }
  | AlignAffine
    { smatch      ∷ Int
    , smismatch   ∷ Int
    , sindelopen  ∷ Int
    , sindelcont  ∷ Int
    , probabilities ∷ Bool
    , fillweight    ∷ PG.FillWeight
    , temperature   ∷ Double
    }
    deriving (Show,Data,Typeable)

oAlignLinear = AlignLinear
  { smatch        = 2         &= help "match score (2)"
  , smismatch     = (-2)      &= help "mismatch score (-2)"
  , sindel        = (-1)      &= help "in/del score (-1)"
  , probabilities = False     &= help "generate probability plot (it is advisable to pipe in RNAfold input with sequence identifiers)"
  , fillweight    = PG.FWlog  &= help ""
  , temperature   = 0.1
  }

oAlignAffine = AlignAffine
  { smatch = 2
  , smismatch = (-2)
  , sindelopen = (-1)
  , sindelcont = (-1)
  , probabilities = False
  , fillweight = PG.FWlog
  , temperature   = 0.1
  }

main ∷ IO ()
main = do
  o ← cmdArgs $ modes [oAlignLinear &= auto, oAlignAffine]
  case o of
    AlignLinear{} → runAlignLinear o
    AlignAffine{} → runAlignAffine o

-- | Read in pairs of @RNAfold@ outputs which are then fed to the linear
-- version of the tree alignment algorithm.

runAlignLinear ∷ Options → IO ()
runAlignLinear AlignLinear{..} = do
  let go ([]            S.:> r) = return r
      go ([(i,x)]       S.:> r) = return r
      go ([(i,x),(j,y)] S.:> r) = do
        let t1 = mkForest x
        let t2 = mkForest y
        AL.runAlignScoreTrees t1 t2 smatch smismatch sindel
        when probabilities $ do
          let fp' = x^.sequenceID.unpackedChars ++ y^.sequenceID.unpackedChars
          let fp = (++ "-" ++ show i ++ "-" ++ show j ++".eps") $ if null fp' then "prob" else fp'
          let t x = Exp $ fromIntegral x / temperature
          AL.runAlignScoreTreesIO
            fillweight PG.EPS
            fp
            t1 t2
            (t smatch) (t smismatch) (t sindel)
        return r
      go ∷ SP.Of [(Int,RNAfold)] a → IO a
  rest ← Q.getContents
       & A.parsed (RNAfold.pRNAfold RNAfold.ForceRNA 37)
       & void
       & SP.zip (SP.each [1..])
       & S.chunksOf 2
       & S.mapped SP.toList
       & S.mapsM_ go
  return ()

runAlignAffine ∷ Options → IO ()
runAlignAffine AlignAffine{..} = do
  let go ([]            S.:> r) = return r
      go ([(i,x)]       S.:> r) = return r
      go ([(i,x),(j,y)] S.:> r) = do
        let t1 = mkForest x
        let t2 = mkForest y
        AA.runAlignScoreTrees t1 t2 smatch smismatch sindelopen sindelcont
        when probabilities $ do
          let fp' = x^.sequenceID.unpackedChars ++ y^.sequenceID.unpackedChars
          let fp = (++ "-" ++ show i ++ "-" ++ show j ++".eps") $ if null fp' then "prob" else fp'
          let t x = Exp $ fromIntegral x / temperature
          AA.runAlignScoreTreesIO
            fillweight PG.EPS
            fp
            t1 t2
            (t smatch) (t smismatch) (t sindelopen) (t sindelcont)
        return r
      go ∷ SP.Of [(Int,RNAfold)] a → IO a
  rest ← Q.getContents
       & A.parsed (RNAfold.pRNAfold RNAfold.ForceRNA 37)
       & void
       & SP.zip (SP.each [1..])
       & S.chunksOf 2
       & S.mapped SP.toList
       & S.mapsM_ go
  return ()

mkForest ∷ RNAfold → Forest 'Pre V.Vector Info
mkForest x = forestPre [toTree (const $ Just $ Info "" 0) (Info "" 0) . either (error . show) id . parseVienna $ x^.mfe.foldedStructure.rnass]