0 | ||| Utilities for computing molecular descriptors
 1 | module Chem.QSAR.Util
 2 |
 3 | import Chem
 4 | import Chem.Aromaticity
 5 | import Chem.AtomType
 6 |
 7 | %default total
 8 |
 9 | parameters {0 b,e,c,p,r,t,ch,l : Type}
10 |            (g : IGraph k b (Atom e c p r h t ch l))
11 |
12 |   ||| Returns the element at the given position
13 |   export
14 |   elemAt : Cast e Elem => Fin k -> Elem
15 |   elemAt = cast . elem . lab g
16 |
17 |   ||| True, if the given node is an atom of the given element
18 |   export %inline
19 |   isElem : Cast e Elem => Elem -> Fin k -> Bool
20 |   isElem el = (el ==) . cast . elem . lab g
21 |   
22 |   ||| True, if the given list of neighbours points to at least one
23 |   ||| element of the given type
24 |   export %inline
25 |   hasElem : Cast e Elem => Elem -> AssocList k b -> Bool
26 |   hasElem el = any (isElem el) . keys
27 |
28 |   ||| True, if the given list of neighbours points to at least one
29 |   ||| element of the given type, bound via a bond of the given order
30 |   export %inline
31 |   hasNeighbour : 
32 |        {auto ce : Cast e Elem}
33 |     -> {auto cb : Cast b BondOrder}
34 |     -> Elem
35 |     -> BondOrder
36 |     -> Fin k
37 |     -> Bool
38 |   hasNeighbour el o =
39 |     any (\(x,v) => cast v == o && isElem el x) . neighboursAsPairs g
40 |
41 |   ||| Counts the number of neighbours pointing to an element of the
42 |   ||| given type.
43 |   export %inline
44 |   countElems : Cast e Elem => Elem -> AssocList k b -> Nat
45 |   countElems el = count (isElem el) . keys
46 |
47 |   ||| Counts the number of non-hydrogen neighbours
48 |   export %inline
49 |   countNonHs : Cast e Elem => AssocList k b -> Nat
50 |   countNonHs = count (not . isElem H) . keys
51 |
52 |   ||| Number of non-hydrogens bound to the given node
53 |   export %inline
54 |   heavyDegree : Cast e Elem => Fin k -> Nat
55 |   heavyDegree = countNonHs . neighboursAsAL g
56 |
57 |   ||| Maximum order of bonds connecting the given node
58 |   export %inline
59 |   maxBondOrder : Cast b BondOrder => Fin k -> BondOrder
60 |   maxBondOrder =
61 |     foldl (\o,(_,vb) => max o $ cast vb) Single . neighboursAsPairs g
62 |
63 |   ||| True, if the bond connecting the two nodes `x` and `y` is an
64 |   ||| amide bond. We assume, that it has already been verified that x and
65 |   ||| are connected via a single bond.
66 |   export
67 |   isAmideBond : Cast e Elem => Cast b BondOrder => (x,y : Fin k) -> Bool
68 |   isAmideBond x y =
69 |     (isElem N x && hasNeighbour O Dbl y) ||
70 |     (isElem N y && hasNeighbour O Dbl x)
71 |
72 | parameters {auto cb : Cast b BondOrder}
73 |
74 |   ||| Accumulates the total bond count from an atoms neighbours and the implicit
75 |   ||| hydrogen count.
76 |   export
77 |   bonds : HCount -> AssocList k b -> Bonds
78 |   bonds hc a = BS (cast hc.value) 0 0 <+> foldMap (toBonds . cast) a
79 |
80 |   ||| Like `bonds` but counts only non-aromatic bonds.
81 |   export
82 |   nonAromaticBonds : HCount -> AssocList k (AromBond b) -> Bonds
83 |   nonAromaticBonds hc a = BS (cast hc.value) 0 0 <+> foldMap conv a
84 |     where
85 |       conv : AromBond b -> Bonds
86 |       conv ab = if ab.arom then neutral else toBonds (cast ab.type)
87 |
88 | ||| Total number of neighbours of an atom (including implicit hydrogens)
89 | export
90 | numNeighbours : Atom e c p r HCount t ch l -> AssocList k b -> Nat
91 | numNeighbours a ns = cast a.hydrogen.value + length ns
92 |