metal.ts 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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. * based in part on NGL (https://github.com/arose/ngl)
  7. */
  8. import { ParamDefinition as PD } from '../../../mol-util/param-definition';
  9. import { Structure, Unit, StructureElement } from '../../../mol-model/structure';
  10. import { FeaturesBuilder, Features } from './features';
  11. import { typeSymbol, compId, atomId } from '../chemistry/util';
  12. import { Elements, isTransitionMetal, isHalogen } from '../../../mol-model/structure/model/properties/atomic/types';
  13. import { FeatureType, FeatureGroup, InteractionType } from './common';
  14. import { LinkProvider } from './links';
  15. import { ElementSymbol, AminoAcidNames, BaseNames, ProteinBackboneAtoms, NucleicBackboneAtoms } from '../../../mol-model/structure/model/types';
  16. export const MetalCoordinationParams = {
  17. distanceMax: PD.Numeric(3.0, { min: 1, max: 5, step: 0.1 }),
  18. }
  19. export type MetalCoordinationParams = typeof MetalCoordinationParams
  20. export type MetalCoordinationProps = PD.Values<MetalCoordinationParams>
  21. const IonicTypeMetals = [
  22. Elements.LI, Elements.NA, Elements.K, Elements.RB, Elements.CS,
  23. Elements.MG, Elements.CA, Elements.SR, Elements.BA, Elements.AL,
  24. Elements.GA, Elements.IN, Elements.TL, Elements.SC, Elements.SN,
  25. Elements.PB, Elements.BI, Elements.SB, Elements.HG
  26. ] as ElementSymbol[]
  27. function addMetal(structure: Structure, unit: Unit.Atomic, builder: FeaturesBuilder) {
  28. const { elements } = unit
  29. const { x, y, z } = unit.model.atomicConformation
  30. for (let i = 0 as StructureElement.UnitIndex, il = elements.length; i < il; ++i) {
  31. const element = typeSymbol(unit, i)
  32. let type = FeatureType.None
  33. if (IonicTypeMetals.includes(element)) {
  34. type = FeatureType.IonicTypeMetal
  35. } else if (isTransitionMetal(element) || element === Elements.ZN || element === Elements.CD) {
  36. type = FeatureType.TransitionMetal
  37. }
  38. if (type) {
  39. builder.add(type, FeatureGroup.None, x[elements[i]], y[elements[i]], z[elements[i]], i)
  40. }
  41. }
  42. }
  43. function isProteinSidechain(atomname: string) {
  44. return !ProteinBackboneAtoms.has(atomname)
  45. }
  46. function isProteinBackbone(atomname: string) {
  47. return ProteinBackboneAtoms.has(atomname)
  48. }
  49. function isNucleicBackbone(atomname: string) {
  50. return NucleicBackboneAtoms.has(atomname)
  51. }
  52. /**
  53. * Metal binding partners (dative bond or ionic-type interaction)
  54. */
  55. function addMetalBinding(structure: Structure, unit: Unit.Atomic, builder: FeaturesBuilder) {
  56. const { elements } = unit
  57. const { x, y, z } = unit.model.atomicConformation
  58. for (let i = 0 as StructureElement.UnitIndex, il = elements.length; i < il; ++i) {
  59. const element = typeSymbol(unit, i)
  60. const resname = compId(unit, i)
  61. const atomname = atomId(unit, i)
  62. let dative = false
  63. let ionic = false
  64. const isStandardAminoacid = AminoAcidNames.has(resname)
  65. const isStandardBase = BaseNames.has(resname)
  66. if (!isStandardAminoacid && !isStandardBase) {
  67. if (isHalogen(element) || element === Elements.O || element === Elements.S) {
  68. dative = true
  69. ionic = true
  70. } else if (element === Elements.N) {
  71. dative = true
  72. }
  73. } else if (isStandardAminoacid) {
  74. // main chain oxygen atom or oxygen, nitrogen and sulfur from specific amino acids
  75. if (element === Elements.O) {
  76. if (['ASP', 'GLU', 'SER', 'THR', 'TYR', 'ASN', 'GLN'].includes(resname) && isProteinSidechain(atomname)) {
  77. dative = true
  78. ionic = true
  79. } else if (isProteinBackbone(atomname)) {
  80. dative = true
  81. ionic = true
  82. }
  83. } else if (element === Elements.S && 'CYS' === resname) {
  84. dative = true
  85. ionic = true
  86. } else if (element === Elements.N) {
  87. if (resname === 'HIS' && isProteinSidechain(atomname)) {
  88. dative = true
  89. }
  90. }
  91. } else if (isStandardBase) {
  92. // http://pubs.acs.org/doi/pdf/10.1021/acs.accounts.6b00253
  93. // http://onlinelibrary.wiley.com/doi/10.1002/anie.200900399/full
  94. if (element === Elements.O && isNucleicBackbone(atomname)) {
  95. dative = true
  96. ionic = true
  97. } else if (['N3', 'N4', 'N7'].includes(atomname)) {
  98. dative = true
  99. } else if (['O2', 'O4', 'O6'].includes(atomname)) {
  100. dative = true
  101. ionic = true
  102. }
  103. }
  104. if (dative) {
  105. builder.add(FeatureType.DativeBondPartner, FeatureGroup.None, x[elements[i]], y[elements[i]], z[elements[i]], i)
  106. }
  107. if (ionic) {
  108. builder.add(FeatureType.IonicTypePartner, FeatureGroup.None, x[elements[i]], y[elements[i]], z[elements[i]], i)
  109. }
  110. }
  111. }
  112. function isMetalCoordination(ti: FeatureType, tj: FeatureType) {
  113. if (ti === FeatureType.TransitionMetal) {
  114. return (
  115. tj === FeatureType.DativeBondPartner ||
  116. tj === FeatureType.TransitionMetal
  117. )
  118. } else if (ti === FeatureType.IonicTypeMetal) {
  119. return (
  120. tj === FeatureType.IonicTypePartner
  121. )
  122. }
  123. }
  124. function testMetalCoordination(structure: Structure, infoA: Features.Info, infoB: Features.Info, distanceSq: number): InteractionType | undefined {
  125. const typeA = infoA.types[infoA.feature]
  126. const typeB = infoB.types[infoB.feature]
  127. if (!isMetalCoordination(typeA, typeB) && !isMetalCoordination(typeB, typeA)) return
  128. return InteractionType.MetalCoordination
  129. }
  130. //
  131. export const MetalProvider = Features.Provider([FeatureType.IonicTypeMetal, FeatureType.TransitionMetal], addMetal)
  132. export const MetalBindingProvider = Features.Provider([FeatureType.IonicTypePartner, FeatureType.DativeBondPartner], addMetalBinding)
  133. export const MetalCoordinationProvider: LinkProvider<MetalCoordinationParams> = {
  134. name: 'metal-coordination',
  135. params: MetalCoordinationParams,
  136. createTester: (props: MetalCoordinationProps) => {
  137. return {
  138. maxDistance: props.distanceMax,
  139. requiredFeatures: new Set([FeatureType.IonicTypeMetal, FeatureType.TransitionMetal, FeatureType.IonicTypePartner, FeatureType.DativeBondPartner]),
  140. getType: (structure, infoA, infoB, distanceSq) => testMetalCoordination(structure, infoA, infoB, distanceSq)
  141. }
  142. }
  143. }