interactions.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  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 { ParamDefinition as PD } from '../../../mol-util/param-definition';
  7. import { Structure, Unit } from '../../../mol-model/structure';
  8. import { RuntimeContext } from '../../../mol-task';
  9. import { Features, FeaturesBuilder } from './features';
  10. import { ValenceModelProvider } from '../valence-model';
  11. import { InteractionsIntraLinks, InteractionsInterLinks } from './common';
  12. import { IntraLinksBuilder, InterLinksBuilder } from './builder';
  13. import { IntMap } from '../../../mol-data/int';
  14. import { Vec3 } from '../../../mol-math/linear-algebra';
  15. import { addUnitLinks, LinkTester, addStructureLinks } from './links';
  16. import { addUnitHalogenDonors, addUnitHalogenAcceptors, HalogenBondsProvider } from './halogen-bonds';
  17. import { addUnitHydrogenDonors, addUnitWeakHydrogenDonors, addUnitHydrogenAcceptors, HydrogenBondsProvider } from './hydrogen-bonds';
  18. export { Interactions }
  19. interface Interactions {
  20. /** Features of each unit */
  21. unitsFeatures: IntMap<Features>
  22. /** Interactions of each unit */
  23. unitsLinks: IntMap<InteractionsIntraLinks>
  24. /** Interactions between units */
  25. links: InteractionsInterLinks
  26. }
  27. namespace Interactions {
  28. export interface Location {
  29. readonly kind: 'interaction-location'
  30. interactions: Interactions
  31. unitA: Unit
  32. /** Index into features of unitA */
  33. indexA: number
  34. unitB: Unit
  35. /** Index into features of unitB */
  36. indexB: number
  37. }
  38. export function Location(interactions?: Interactions, unitA?: Unit, indexA?: number, unitB?: Unit, indexB?: number): Location {
  39. return { kind: 'interaction-location', interactions: interactions as any, unitA: unitA as any, indexA: indexA as any, unitB: unitB as any, indexB: indexB as any };
  40. }
  41. export function isLocation(x: any): x is Location {
  42. return !!x && x.kind === 'interaction-location';
  43. }
  44. export function areLocationsEqual(locA: Location, locB: Location) {
  45. return (
  46. locA.interactions === locB.interactions &&
  47. locA.indexA === locB.indexA && locA.indexB === locB.indexB &&
  48. locA.unitA === locB.unitA && locA.unitB === locB.unitB
  49. )
  50. }
  51. export interface Loci {
  52. readonly kind: 'interaction-loci'
  53. readonly structure: Structure
  54. readonly interactions: Interactions
  55. readonly links: ReadonlyArray<{
  56. unitA: Unit
  57. /** Index into features of unitA */
  58. indexA: number
  59. unitB: Unit
  60. /** Index into features of unitB */
  61. indexB: number
  62. }>
  63. }
  64. export function Loci(structure: Structure, interactions: Interactions, links: Loci['links']): Loci {
  65. return { kind: 'interaction-loci', structure, interactions, links };
  66. }
  67. export function isLoci(x: any): x is Loci {
  68. return !!x && x.kind === 'interaction-loci';
  69. }
  70. export function areLociEqual(a: Loci, b: Loci) {
  71. if (a.structure !== b.structure) return false
  72. if (a.interactions !== b.interactions) return false
  73. if (a.links.length !== b.links.length) return false
  74. for (let i = 0, il = a.links.length; i < il; ++i) {
  75. const linkA = a.links[i]
  76. const linkB = b.links[i]
  77. if (linkA.unitA !== linkB.unitA) return false
  78. if (linkA.unitB !== linkB.unitB) return false
  79. if (linkA.indexA !== linkB.indexA) return false
  80. if (linkA.indexB !== linkB.indexB) return false
  81. }
  82. return true
  83. }
  84. export function isLociEmpty(loci: Loci) {
  85. return loci.links.length === 0 ? true : false
  86. }
  87. }
  88. export const InteractionsParams = {
  89. hydrogenBonds: PD.Group(HydrogenBondsProvider.params),
  90. halogenBonds: PD.Group(HalogenBondsProvider.params),
  91. }
  92. export type InteractionsParams = typeof InteractionsParams
  93. export type InteractionsProps = PD.Values<InteractionsParams>
  94. export async function computeInteractions(runtime: RuntimeContext, structure: Structure, props: Partial<InteractionsProps>) {
  95. const p = { ...PD.getDefaultValues(InteractionsParams), ...props }
  96. await ValenceModelProvider.attach(structure).runInContext(runtime)
  97. const linkTesters: LinkTester[] = [
  98. HydrogenBondsProvider.createTester(p.hydrogenBonds),
  99. HalogenBondsProvider.createTester(p.halogenBonds)
  100. ]
  101. const unitsFeatures = IntMap.Mutable<Features>()
  102. const unitsLinks = IntMap.Mutable<InteractionsIntraLinks>()
  103. for (let i = 0, il = structure.unitSymmetryGroups.length; i < il; ++i) {
  104. const group = structure.unitSymmetryGroups[i]
  105. const d = findIntraUnitLinksAndFeatures(structure, group.units[0], linkTesters)
  106. for (let j = 0, jl = group.units.length; j < jl; ++j) {
  107. const u = group.units[j]
  108. unitsFeatures.set(u.id, d.features)
  109. unitsLinks.set(u.id, d.links)
  110. }
  111. }
  112. const links = findInterUnitLinks(structure, unitsFeatures, linkTesters)
  113. return { unitsFeatures, unitsLinks, links }
  114. }
  115. const FeatureProviders: Features.Provider[] = [
  116. { name: 'hydrogen-donors', add: addUnitHydrogenDonors },
  117. { name: 'weak-hydrogen-donors', add: addUnitWeakHydrogenDonors },
  118. { name: 'hydrogen-acceptors', add: addUnitHydrogenAcceptors },
  119. { name: 'halogen-donors', add: addUnitHalogenDonors },
  120. { name: 'halogen-acceptors', add: addUnitHalogenAcceptors },
  121. ]
  122. function findIntraUnitLinksAndFeatures(structure: Structure, unit: Unit, linkTesters: ReadonlyArray<LinkTester>) {
  123. const count = unit.elements.length
  124. const featuresBuilder = FeaturesBuilder.create(count, count / 2)
  125. if (Unit.isAtomic(unit)) {
  126. for (const featureProvider of FeatureProviders) {
  127. featureProvider.add(structure, unit, featuresBuilder)
  128. }
  129. }
  130. const features = featuresBuilder.getFeatures(count)
  131. const linksBuilder = IntraLinksBuilder.create(features, count)
  132. if (Unit.isAtomic(unit)) {
  133. addUnitLinks(structure, unit, features, linksBuilder, linkTesters)
  134. }
  135. return { features, links: linksBuilder.getLinks() }
  136. }
  137. function findInterUnitLinks(structure: Structure, unitsFeatures: IntMap<Features>, linkTesters: ReadonlyArray<LinkTester>) {
  138. const builder = InterLinksBuilder.create()
  139. const maxDistance = Math.sqrt(Math.max(...linkTesters.map(t => t.maxDistanceSq)))
  140. const lookup = structure.lookup3d;
  141. const imageCenter = Vec3.zero();
  142. for (const unitA of structure.units) {
  143. if (!Unit.isAtomic(unitA)) continue;
  144. const featuresA = unitsFeatures.get(unitA.id)
  145. const bs = unitA.lookup3d.boundary.sphere;
  146. Vec3.transformMat4(imageCenter, bs.center, unitA.conformation.operator.matrix);
  147. const closeUnits = lookup.findUnitIndices(imageCenter[0], imageCenter[1], imageCenter[2], bs.radius + maxDistance);
  148. for (let i = 0; i < closeUnits.count; i++) {
  149. const unitB = structure.units[closeUnits.indices[i]];
  150. if (!Unit.isAtomic(unitB) || unitA.id >= unitB.id || !Structure.validUnitPair(structure, unitA, unitB)) continue;
  151. const featuresB = unitsFeatures.get(unitB.id)
  152. if (unitB.elements.length >= unitA.elements.length) {
  153. addStructureLinks(structure, unitA, featuresA, unitB, featuresB, builder, linkTesters)
  154. } else {
  155. addStructureLinks(structure, unitB, featuresB, unitA, featuresA, builder, linkTesters)
  156. }
  157. }
  158. }
  159. return builder.getLinks()
  160. }