packages feed

cobot-io 0.1.2.8 → 0.1.2.9

raw patch · 8 files changed

+166/−17 lines, 8 filesPVP: minor bump suggested

API additions: PVP suggests at least a minor version bump

API changes (from Hackage documentation)

+ Bio.Structure: instance GHC.Base.Functor Bio.Structure.Bond
+ Bio.Structure: instance GHC.Classes.Ord (Bio.Structure.Bond Bio.Structure.GlobalID)
+ Bio.Structure: instance GHC.Classes.Ord (Bio.Structure.Bond Bio.Structure.LocalID)
+ Bio.Structure: instance GHC.Classes.Ord Bio.Structure.GlobalID
+ Bio.Structure: instance GHC.Classes.Ord Bio.Structure.LocalID
+ Bio.Structure.Functions: filterAtomsOfModel :: (Atom -> Bool) -> Model -> Model

Files

ChangeLog.md view
@@ -2,6 +2,12 @@  ## [Unreleased] +## [0.1.2.9] - 2020-03-12+### Added+- Function `filterAtomsOfModel` to filter atoms of model by the given predicate.+### Fixed+- Grouping by residues when converting `Mae` to `Model`.+ ## [0.1.2.8] - 2020-03-12 ### Added - `instance Traversable (Sequence mk w)`.
cobot-io.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 43e7df0f9593c9d406051c22f2a7ae31d13535e94800fe30c9a692b205071e15+-- hash: 4620b896cb4c841495a5d9ff83d8f260a4d186408209a552e2d82175aa208b2d  name:           cobot-io-version:        0.1.2.8+version:        0.1.2.9 synopsis:       Biological data file formats and IO description:    Please see the README on GitHub at <https://github.com/less-wrong/cobot-io#readme> category:       Bio@@ -62,6 +62,7 @@       Bio.Sequence.Functions.Weight       Bio.Sequence.Utilities       Bio.Structure+      Bio.Structure.Functions       Bio.Uniprot       Bio.Uniprot.Parser       Bio.Uniprot.Type@@ -104,6 +105,7 @@       MMTFSpec       PDBSpec       SequenceSpec+      StructureSpec       UniprotSpec       Paths_cobot_io   hs-source-dirs:
src/Bio/MAE.hs view
@@ -1,5 +1,5 @@-{-# LANGUAGE CPP #-} {-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE CPP                 #-} {-# OPTIONS_GHC -fno-warn-orphans #-}  module Bio.MAE@@ -36,7 +36,7 @@ import qualified Data.Vector            as V (fromList) import           Linear.V3              (V3 (..)) #if !MIN_VERSION_base(4,13,0)-import           Control.Monad.Fail     (MonadFail(..))+import           Control.Monad.Fail     (MonadFail (..)) import           Prelude                hiding (fail) #endif @@ -118,7 +118,7 @@                   residues          = V.fromList $ fmap groupToResidue groupedByResidues                    by :: Int -> (Int, Text)-                  by i = (unsafeGetFromContents "i_m_residue_number" i, unsafeGetFromContents "s_m_pdb_residue_name" i)+                  by i = (unsafeGetFromContents "i_m_residue_number" i, getFromContents defaultChainName "s_m_insertion_code" i)                defaultChainName :: Text               defaultChainName = "A"
src/Bio/Structure.hs view
@@ -31,10 +31,10 @@ instance NFData SecondaryStructure  newtype GlobalID = GlobalID { getGlobalID :: Int }-  deriving (Eq, Show, Generic, NFData)+  deriving (Eq, Show, Ord, Generic, NFData)  newtype LocalID  = LocalID { getLocalID :: Int }-  deriving (Eq, Show, Generic, NFData)+  deriving (Eq, Show, Ord, Generic, NFData)  -- | Generic atom representation --@@ -56,7 +56,15 @@                    , bondEnd   :: m    -- ^ index of second incident atom                    , bondOrder :: Int  -- ^ the order of chemical bond                    }-  deriving (Show, Eq, Generic)+  deriving (Show, Eq, Functor, Generic)++instance Ord (Bond LocalID) where+    (Bond (LocalID x) (LocalID y) _) <= (Bond (LocalID x') (LocalID y') _) | x == x'   = y <= y'+                                                                           | otherwise = x <= x'++instance Ord (Bond GlobalID) where+    (Bond (GlobalID x) (GlobalID y) _) <= (Bond (GlobalID x') (GlobalID y') _) | x == x'   = y <= y'+                                                                               | otherwise = x <= x'  instance NFData a => NFData (Bond a) 
+ src/Bio/Structure/Functions.hs view
@@ -0,0 +1,59 @@+module Bio.Structure.Functions+  ( filterAtomsOfModel+  ) where++import           Bio.Structure   (Atom (..), Bond (..), Chain (..),+                                  GlobalID (..), LocalID (..), Model (..),+                                  Residue (..))+import qualified Data.Map.Strict as M (fromList, (!))+import           Data.Set        (Set)+import qualified Data.Set        as S (fromList, notMember, unions)+import           Data.Vector     (Vector)+import qualified Data.Vector     as V (filter, fromList, length, toList, unzip)++-- | Takes predicate on 'Atom's of 'Model' and returns new 'Model' containing only atoms+--   satisfying given predicate.+--+filterAtomsOfModel :: (Atom -> Bool) -> Model -> Model+filterAtomsOfModel p Model{..} = Model newChains newBonds+  where+    removePred         = not . p+    (newChains, indss) = V.unzip $ fmap (removeAtomsFromChain removePred) modelChains++    inds     = S.unions $ V.toList indss+    newBonds = V.filter (\(Bond l r _) -> l `S.notMember` inds && r `S.notMember` inds) modelBonds++removeAtomsFromChain :: (Atom -> Bool) -> Chain -> (Chain, Set GlobalID)+removeAtomsFromChain p Chain{..} = (Chain chainName newResidues, S.unions $ V.toList indss)+  where+    (newResidues, indss) = V.unzip $ fmap (removeAtomsFromResidue p) chainResidues++removeAtomsFromResidue :: (Atom -> Bool) -> Residue -> (Residue, Set GlobalID)+removeAtomsFromResidue p r'@Residue{..} = (res, S.fromList $ V.toList $ fmap atomId withAtom)+  where+    (withAtom, withoutAtom, indsToDelete) = partitionAndInds resAtoms++    oldIndsToNew = M.fromList $ fmap (\i -> (i, newInd i)) [0 .. V.length resAtoms - 1]+    newBonds     = fmap modifyBond $ V.filter leaveBond resBonds++    res = r' { resAtoms=withoutAtom, resBonds=newBonds }++    leaveBond :: Bond LocalID -> Bool+    leaveBond (Bond (LocalID l) (LocalID r) _) = l `notElem` indsToDelete && r `notElem` indsToDelete++    modifyBond :: Bond LocalID -> Bond LocalID+    modifyBond (Bond (LocalID l) (LocalID r) t) = Bond (LocalID $ oldIndsToNew M.! l)+                                                       (LocalID $ oldIndsToNew M.! r)+                                                       t++    newInd :: Int -> Int+    newInd i = i - (length $ filter (< i) indsToDelete)++    partitionAndInds :: Vector Atom -> (Vector Atom, Vector Atom, [Int])+    partitionAndInds = go 0 ([], [], []) . V.toList+      where+        go :: Int -> ([Atom], [Atom], [Int]) -> [Atom] -> (Vector Atom, Vector Atom, [Int])+        go _ (sat, notSat, inds) []       = (V.fromList $ reverse sat, V.fromList $ reverse notSat, reverse inds)+        go i (sat, notSat, inds) (x : xs) = go (i + 1) newState xs+          where+            newState = if p x then (x : sat, notSat, i : inds) else (sat, x : notSat, inds)
test/MAESpec.hs view
@@ -88,11 +88,3 @@      toSet :: Ord a => Vector a -> Set a     toSet = S.fromList . V.toList--instance Ord (Bond LocalID) where-    (Bond (LocalID x) (LocalID y) _) <= (Bond (LocalID x') (LocalID y') _) | x == x'   = y <= y'-                                                                           | otherwise = x <= x'--instance Ord (Bond GlobalID) where-    (Bond (GlobalID x) (GlobalID y) _) <= (Bond (GlobalID x') (GlobalID y') _) | x == x'   = y <= y'-                                                                               | otherwise = x <= x'
test/Spec.hs view
@@ -7,11 +7,12 @@ import           MAEParserSpec import           MAESpec import           MMTFSpec+import           PDBSpec import           SequenceSpec+import           StructureSpec import           System.IO import           Test.Hspec import           UniprotSpec-import           PDBSpec  main :: IO () main = do@@ -52,3 +53,5 @@          repeatedStringsSpecP          emptyRemarkSpecP          emptyModelSpecP+         -- Structure+         structureSpec
+ test/StructureSpec.hs view
@@ -0,0 +1,79 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module StructureSpec where++import           Bio.MAE                 (fromFile)+import           Bio.Structure           (Atom (..), Bond (..), Chain (..),+                                          LocalID (..), Model (..),+                                          Residue (..), StructureModels (..))+import           Bio.Structure.Functions (filterAtomsOfModel)+import           Control.Monad           (join)+import           Data.Map.Strict         (Map)+import qualified Data.Map.Strict         as M (fromList, (!))+import           Data.Maybe              (fromJust, isJust)+import           Data.Set                (Set)+import qualified Data.Set                as S (fromList, member)+import           Data.Vector             (Vector)+import qualified Data.Vector             as V (all, filter, find, fromList,+                                               toList, zip)+import           Test.Hspec++structureSpec :: Spec+structureSpec = describe "Structure spec." $ do+    m <- runIO $ V.toList . modelsOf <$> fromFile "test/MAE/Capri.mae" >>= \[x] -> pure x++    it "atoms filtering works correctly. only N, CA, C"  $ checkFiltering m $ (`elem` ["N", "CA", "C"]) . atomName+    it "atoms filtering works correctly. only CA"        $ checkFiltering m $ (== "CA") . atomName+    it "atoms filtering works correctly. no atoms"       $ checkFiltering m $ const False+    it "atoms filtering works correctly. all atoms"      $ checkFiltering m $ const True+  where+    checkFiltering :: Model -> (Atom -> Bool) -> Expectation+    checkFiltering m p = do+        checkAtoms+        checkGlobalBonds+        checkLocalBonds+      where+        m' = filterAtomsOfModel p m++        checkAtoms :: Expectation+        checkAtoms = V.all (V.all (V.all p . resAtoms) . chainResidues) (modelChains m') `shouldBe` True++        checkGlobalBonds :: Expectation+        checkGlobalBonds = all (\(Bond l r _) -> l `S.member` inds && r `S.member` inds) (modelBonds m') `shouldBe` True+          where+            filteredAtoms = join $ fmap (join . fmap (V.filter p . resAtoms) . chainResidues) $ modelChains m+            inds          = vecToSet $ fmap atomId filteredAtoms++        checkLocalBonds :: Expectation+        checkLocalBonds = all checkResiduePair pairsOfResidues `shouldBe` True+          where+            pairsOfResidues = zip (V.toList (join $ chainResidues <$> modelChains m))+                                  (V.toList (join $ chainResidues <$> modelChains m'))++            checkResiduePair :: (Residue, Residue) -> Bool+            checkResiduePair (r, r') = vecToSet mappedBonds == vecToSet (resBonds r')+              where+                atInds  = atomsWithIndices r+                atInds' = atomsWithIndices r'++                mappedBonds = fromJust <$> V.filter isJust (mapBond <$> resBonds r)++                mapBond :: Bond LocalID -> Maybe (Bond LocalID)+                mapBond (Bond l k t) = Bond <$> localMapping M.! l+                                            <*> localMapping M.! k+                                            <*> pure t++                localMapping :: Map LocalID (Maybe LocalID)+                localMapping = M.fromList $ V.toList forMap+                  where+                    forMap = fmap (\(a, i) -> (i, snd <$> V.find ((== atomId a) . atomId . fst) atInds')) atInds++                atomsWithIndices :: Residue -> Vector (Atom, LocalID)+                atomsWithIndices Residue{..} = V.zip resAtoms $ fmap LocalID $ V.fromList [0 ..]++        vecToSet :: Ord a => Vector a -> Set a+        vecToSet = S.fromList . V.toList+