{-# LANGUAGE TypeSynonymInstances #-}
module Bio.Protein.Chain.Builder
( Buildable (..)
, build
) where
import Data.Ix ( Ix )
import Control.Lens
import Linear.V3 ( V3 (..)
, cross
, _z
)
import Linear.Vector ( negated
, unit
, (*^)
)
import Bio.Utils.Geometry hiding ( angle )
import Bio.Protein.AminoAcid
import Bio.Protein.Chain
class Buildable a where
type Monomer a :: *
initB :: Monomer a -> a
nextB :: Monomer a -> a -> a
build :: forall a m.(Buildable a, ChainLike m, Ix (Index m), IxValue m ~ Monomer a) => m -> ProteinChain (Index m) a
build ch = ProteinChain result
where
result :: Chain (Index m) a
result = chain (bounds ch) [ (i, next i x) | (i, x) <- assocs ch ]
next :: Index m -> Monomer a -> a
next k x | k == fst (bounds ch) = initB x
| otherwise = nextB x (result ! pred k)
instance Buildable (BB V3R) where
type Monomer (BB V3R) = AA
initB _ = let n_ = V3 n_x 0.0 0.0
a_ = V3 0.0 0.0 0.0
c_ = V3 c_x c_y 0.0
n_x = - dist N CA
c_x = dist CA C * cos (pi + angle N CA C)
c_y = dist CA C * sin (pi + angle N CA C)
in create @(BB V3R) n_ a_ c_
nextB _ aa = let
rot = rotate (unit _z)
v21 = aa ^. n . atom - aa ^. ca . atom
v23 = aa ^. c . atom - aa ^. ca . atom
cw = if (v21 `cross` v23) ^. _z < 0 then 1.0 else -1.0 :: R
v32 = negated v23
v34 = dist C N *^ rot (cw * angle CA C N) (normalize v32)
n_ = aa ^. c . atom + v34
v43 = negated v34
v45 = dist N CA *^ rot (-cw * angle C N CA) (normalize v43)
ca_ = n_ + v45
v54 = negated v45
v56 = dist CA C *^ rot (cw * angle N CA C) (normalize v54)
c_ = ca_ + v56
in create @(BB V3R) n_ ca_ c_
instance Buildable (BBT V3R) where
type Monomer (BBT V3R) = AA
initB t = let aa = initB t :: BB V3R
in create @(BBT V3R) (aa ^. n . atom) (aa ^. ca . atom) (aa ^. c . atom) t
nextB t aaT = let aa = create @(BB V3R) (aaT ^. n . atom) (aaT ^. ca . atom) (aaT ^. c . atom)
ab = nextB t aa :: BB V3R
in create @(BBT V3R) (ab ^. n . atom) (ab ^. ca . atom) (ab ^. c . atom) t
data BackboneAtom = N | CA | C
deriving (Show, Eq, Ord, Bounded, Enum)
dist :: BackboneAtom -> BackboneAtom -> R
dist N CA = 1.460
dist CA C = 1.509
dist C N = 1.290
dist x y = dist y x
angle :: BackboneAtom -> BackboneAtom -> BackboneAtom -> R
angle N CA C = pi * 110.990 / 180.0
angle CA C N = pi * 118.995 / 180.0
angle C N CA = angle CA C N
angle x y z = angle z y x