functional-group.ts 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /**
  2. * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { Structure, Unit } from '../../../mol-model/structure';
  7. import { StructureElement } from '../../../mol-model/structure/structure';
  8. import { Elements, isHalogen } from '../../../mol-model/structure/model/properties/atomic/types';
  9. import { ElementSymbol, BondType } from '../../../mol-model/structure/model/types';
  10. import { eachBondedAtom, bondCount, typeSymbol, bondToElementCount } from './util';
  11. function isAromatic(unit: Unit.Atomic, index: StructureElement.UnitIndex) {
  12. // TODO also extend unit.rings with geometry/composition-based aromaticity detection and use it here in addition
  13. const { offset, edgeProps } = unit.bonds
  14. for (let i = offset[index], il = offset[index + 1]; i < il; ++i) {
  15. if (BondType.is(BondType.Flag.Aromatic, edgeProps.flags[i])) return true
  16. }
  17. return false
  18. }
  19. function bondToCarbonylCount(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) {
  20. let carbonylCount = 0
  21. eachBondedAtom(structure, unit, index, (unit: Unit.Atomic, index: StructureElement.UnitIndex) => {
  22. if (isCarbonyl(structure, unit, index)) carbonylCount += 1
  23. })
  24. return carbonylCount
  25. }
  26. //
  27. /**
  28. * Nitrogen in a quaternary amine
  29. */
  30. export function isQuaternaryAmine(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) {
  31. return (
  32. typeSymbol(unit, index) === Elements.N &&
  33. bondCount(structure, unit, index) === 4 &&
  34. bondToElementCount(structure, unit, index, Elements.H) === 0
  35. )
  36. }
  37. /**
  38. * Nitrogen in a tertiary amine
  39. */
  40. export function isTertiaryAmine(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex, idealValence: number) {
  41. return (
  42. typeSymbol(unit, index) === Elements.N &&
  43. bondCount(structure, unit, index) === 4 &&
  44. idealValence === 3
  45. )
  46. }
  47. /**
  48. * Nitrogen in an imide
  49. */
  50. export function isImide(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) {
  51. let flag = false
  52. if (typeSymbol(unit, index) === Elements.N &&
  53. (bondCount(structure, unit, index) - bondToElementCount(structure, unit, index, Elements.H)) === 2
  54. ) {
  55. flag = bondToCarbonylCount(structure, unit, index) === 2
  56. }
  57. return flag
  58. }
  59. /**
  60. * Nitrogen in an amide
  61. */
  62. export function isAmide(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) {
  63. let flag = false
  64. if (typeSymbol(unit, index) === Elements.N &&
  65. (bondCount(structure, unit, index) - bondToElementCount(structure, unit, index, Elements.H)) === 2
  66. ) {
  67. flag = bondToCarbonylCount(structure, unit, index) === 1
  68. }
  69. return flag
  70. }
  71. /**
  72. * Sulfur in a sulfonium group
  73. */
  74. export function isSulfonium(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) {
  75. return (
  76. typeSymbol(unit, index) === Elements.S &&
  77. bondCount(structure, unit, index) === 3 &&
  78. bondToElementCount(structure, unit, index, Elements.H) === 0
  79. )
  80. }
  81. /**
  82. * Sulfur in a sulfonic acid or sulfonate group
  83. */
  84. export function isSulfonicAcid(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) {
  85. return (
  86. typeSymbol(unit, index) === Elements.S &&
  87. bondToElementCount(structure, unit, index, Elements.O) === 3
  88. )
  89. }
  90. /**
  91. * Sulfur in a sulfate group
  92. */
  93. export function isSulfate(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) {
  94. return (
  95. typeSymbol(unit, index) === Elements.S &&
  96. bondToElementCount(structure, unit, index, Elements.O) === 4
  97. )
  98. }
  99. /**
  100. * Phosphor in a phosphate group
  101. */
  102. export function isPhosphate (structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) {
  103. return (
  104. typeSymbol(unit, index) === Elements.P &&
  105. bondToElementCount(structure, unit, index, Elements.O) === bondCount(structure, unit, index)
  106. )
  107. }
  108. /**
  109. * Halogen with one bond to a carbon
  110. */
  111. export function isHalocarbon (structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) {
  112. return (
  113. isHalogen(typeSymbol(unit, index)) &&
  114. bondCount(structure, unit, index) === 1 &&
  115. bondToElementCount(structure, unit, index, Elements.C) === 1
  116. )
  117. }
  118. /**
  119. * Carbon in a carbonyl/acyl group
  120. *
  121. * TODO currently only checks intra bonds for group detection
  122. */
  123. export function isCarbonyl(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) {
  124. let flag = false
  125. if (typeSymbol(unit, index) === Elements.C) {
  126. const { offset, edgeProps, b } = unit.bonds
  127. for (let i = offset[index], il = offset[index + 1]; i < il; ++i) {
  128. if (edgeProps.order[i] === 2 && typeSymbol(unit, b[i] as StructureElement.UnitIndex) === Elements.O) {
  129. flag = true
  130. break
  131. }
  132. }
  133. }
  134. return flag
  135. }
  136. /**
  137. * Carbon in a carboxylate group
  138. */
  139. export function isCarboxylate (structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) {
  140. let terminalOxygenCount = 0
  141. if (
  142. typeSymbol(unit, index) === Elements.C &&
  143. bondToElementCount(structure, unit, index, Elements.O) === 2 &&
  144. bondToElementCount(structure, unit, index, Elements.C) === 1
  145. ) {
  146. eachBondedAtom(structure, unit, index, (unit: Unit.Atomic, index: StructureElement.UnitIndex) => {
  147. if (
  148. typeSymbol(unit, index) === Elements.O &&
  149. bondCount(structure, unit, index) - bondToElementCount(structure, unit, index, Elements.H) === 1
  150. ) {
  151. terminalOxygenCount += 1
  152. }
  153. })
  154. }
  155. return terminalOxygenCount === 2
  156. }
  157. /**
  158. * Carbon in a guanidine group
  159. */
  160. export function isGuanidine (structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) {
  161. let terminalNitrogenCount = 0
  162. if (
  163. typeSymbol(unit, index) === Elements.C &&
  164. bondCount(structure, unit, index) === 3 &&
  165. bondToElementCount(structure, unit, index, Elements.N) === 3
  166. ) {
  167. eachBondedAtom(structure, unit, index, (unit: Unit.Atomic, index: StructureElement.UnitIndex) => {
  168. if (
  169. bondCount(structure, unit, index) - bondToElementCount(structure, unit, index, Elements.H) === 1
  170. ) {
  171. terminalNitrogenCount += 1
  172. }
  173. })
  174. }
  175. return terminalNitrogenCount === 2
  176. }
  177. /**
  178. * Carbon in a acetamidine group
  179. */
  180. export function isAcetamidine (structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) {
  181. let terminalNitrogenCount = 0
  182. if (
  183. typeSymbol(unit, index) === Elements.C &&
  184. bondCount(structure, unit, index) === 3 &&
  185. bondToElementCount(structure, unit, index, Elements.N) === 2 &&
  186. bondToElementCount(structure, unit, index, Elements.C) === 1
  187. ) {
  188. eachBondedAtom(structure, unit, index, (unit: Unit.Atomic, index: StructureElement.UnitIndex) => {
  189. if (
  190. bondCount(structure, unit, index) - bondToElementCount(structure, unit, index, Elements.H) === 1
  191. ) {
  192. terminalNitrogenCount += 1
  193. }
  194. })
  195. }
  196. return terminalNitrogenCount === 2
  197. }
  198. const PolarElements = new Set<ElementSymbol>([ 'N', 'O', 'S', 'F', 'CL', 'BR', 'I' ] as ElementSymbol[])
  199. export function isPolar(element: ElementSymbol) { return PolarElements.has(element) }
  200. export function hasPolarNeighbour (structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) {
  201. let flag = false
  202. eachBondedAtom(structure, unit, index, (unit: Unit.Atomic, index: StructureElement.UnitIndex) => {
  203. if (isPolar(typeSymbol(unit, index))) flag = true
  204. })
  205. return flag
  206. }
  207. export function hasAromaticNeighbour (structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) {
  208. let flag = false
  209. eachBondedAtom(structure, unit, index, (unit: Unit.Atomic, index: StructureElement.UnitIndex) => {
  210. if (isAromatic(unit, index)) flag = true
  211. })
  212. return flag
  213. }