0 | module Text.Smiles.AtomType
 1 |
 2 | import Chem
 3 | import Text.Smiles.Types
 4 |
 5 | %default total
 6 |
 7 | ||| SMILES atom with perceived atom type and computed
 8 | ||| implicit hydrogen count
 9 | public export
10 | 0 SmilesAtomAT : Type
11 | SmilesAtomAT = Atom AromIsotope Charge () () HCount AtomType Chirality ()
12 |
13 | export %inline
14 | Cast SmilesAtomAT Elem where
15 |   cast a = cast a.elem
16 |
17 | export %inline
18 | Cast SmilesAtomAT Hybridization where
19 |   cast a = cast a.type.hybridization
20 |
21 | ||| SMILES molecule with perceived atom type and computed
22 | ||| implicit hydrogen count
23 | public export
24 | 0 SmilesGraphAT : Type
25 | SmilesGraphAT = Graph SmilesBond SmilesAtomAT
26 |
27 | --------------------------------------------------------------------------------
28 | --          Utilities
29 | --------------------------------------------------------------------------------
30 |
31 | sbToBonds : SmilesBond -> Bonds
32 | sbToBonds Sngl = BS 1 0 0
33 | sbToBonds Arom = BS 0 0 0
34 | sbToBonds Dbl  = BS 0 1 0
35 | sbToBonds Trpl = BS 0 0 1
36 | sbToBonds Quad = BS 0 0 0 -- TODO: Should we even support this?
37 | sbToBonds FW   = BS 1 0 0
38 | sbToBonds BW   = BS 1 0 0
39 |
40 | -- Adjust number of bonds for nitrogen-like elements (N, P, As) with
41 | -- two aromatic bonds. If these have no additional single bonds, they are
42 | -- pyridine-like and one of the aromtic bonds should be treated as a double
43 | -- bond. Otherwise, they are pyrrole-like and both aromatic bonds should
44 | -- be counted as single bonds.
45 | adjNitrogen2 : Bonds -> Bonds
46 | adjNitrogen2 bs =
47 |   if bs.single > 0
48 |      then {single $= (+ 2)} bs
49 |      else {single := 1, double $= S} bs
50 |
51 | -- add aromatic bonds to the list of bonds connected to an atom
52 | addAromaticBonds : Elem -> Nat -> Bonds -> Bonds
53 | addAromaticBonds _ 0 bs = bs
54 | addAromaticBonds C 2 bs =
55 |   if bs.double > 0
56 |      then {single $= (+ 2)} bs
57 |      else {single $= S, double $= S} bs
58 | addAromaticBonds C  3 bs = {single $= (+2), double $= S} bs
59 | addAromaticBonds N  2 bs = adjNitrogen2 bs
60 | addAromaticBonds P  2 bs = adjNitrogen2 bs
61 | addAromaticBonds As 2 bs = adjNitrogen2 bs
62 | addAromaticBonds _  n bs = {single $= (+n)} bs
63 |
64 | -- compute the atom type and implicit hydrogen count from
65 | -- a SMILES atom and the list of bonds connected to it
66 | calcAT : Fin k -> Adj k SmilesBond SmilesAtom -> SmilesAtomAT
67 | calcAT n (A at@(SubsetAtom e a) ns) =
68 |   let iso     := MkAI e Nothing a
69 |       arom    := count (Arom ==) ns
70 |       bonds   := addAromaticBonds e arom $ foldMap sbToBonds ns
71 |       (h,tpe) := atomTypeAndHydrogens e NoRadical 0 bonds
72 |    in MkAtom iso 0 () () h tpe None ()
73 |
74 | calcAT n (A (Bracket x) ns) =
75 |   let e    := cast {to = Elem} x.elem
76 |       arom := count (Arom ==) ns
77 |       bs   :=
78 |           addAromaticBonds e arom               -- add aromatic bonds
79 |         . {single $= (+ cast x.hydrogen.value)} -- add bonds to implicit Hs
80 |         $ foldMap sbToBonds ns                    -- compute non-aromatic bonds
81 |    in {type := exactAtomType e NoRadical x.charge bs} x
82 |
83 | export %inline
84 | perceiveSmilesAtomTypes : SmilesGraph -> SmilesGraphAT
85 | perceiveSmilesAtomTypes (G o g) = G o $ mapWithCtxt calcAT g
86 |