cross-links.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. /**
  2. * Copyright (c) 2018 Mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { Model } from '../../../model'
  7. import { Table } from 'mol-data/db'
  8. import { mmCIF_Schema } from 'mol-io/reader/cif/schema/mmcif';
  9. import { findAtomIndexByLabelName } from '../util';
  10. import { Unit } from '../../../../structure';
  11. import { ElementIndex } from '../../../indexing';
  12. function findAtomIndex(model: Model, entityId: string, asymId: string, compId: string, seqId: number, atomId: string) {
  13. if (!model.atomicHierarchy.atoms.auth_atom_id.isDefined) return -1
  14. const residueIndex = model.atomicHierarchy.findResidueKey(entityId, compId, asymId, seqId, '')
  15. if (residueIndex < 0) return -1
  16. return findAtomIndexByLabelName(model, residueIndex, atomId, '') as ElementIndex
  17. }
  18. export interface IHMCrossLinkRestraint {
  19. getIndicesByElement: (element: ElementIndex, kind: Unit.Kind) => number[]
  20. data: Table<mmCIF_Schema['ihm_cross_link_restraint']>
  21. }
  22. export namespace IHMCrossLinkRestraint {
  23. export const PropName = '__CrossLinkRestraint__';
  24. export function fromModel(model: Model): IHMCrossLinkRestraint | undefined {
  25. if (model._staticPropertyData[PropName]) return model._staticPropertyData[PropName]
  26. if (model.sourceData.kind !== 'mmCIF') return
  27. const { ihm_cross_link_restraint } = model.sourceData.data;
  28. if (!ihm_cross_link_restraint._rowCount) return
  29. const p1 = {
  30. entity_id: ihm_cross_link_restraint.entity_id_1,
  31. asym_id: ihm_cross_link_restraint.asym_id_1,
  32. comp_id: ihm_cross_link_restraint.comp_id_1,
  33. seq_id: ihm_cross_link_restraint.seq_id_1,
  34. atom_id: ihm_cross_link_restraint.atom_id_1,
  35. }
  36. const p2: typeof p1 = {
  37. entity_id: ihm_cross_link_restraint.entity_id_2,
  38. asym_id: ihm_cross_link_restraint.asym_id_2,
  39. comp_id: ihm_cross_link_restraint.comp_id_2,
  40. seq_id: ihm_cross_link_restraint.seq_id_2,
  41. atom_id: ihm_cross_link_restraint.atom_id_2,
  42. }
  43. function _add(map: Map<ElementIndex, number[]>, element: ElementIndex, row: number) {
  44. const indices = map.get(element)
  45. if (indices) indices.push(row)
  46. else map.set(element, [ row ])
  47. }
  48. function add(row: number, ps: typeof p1) {
  49. const entityId = ps.entity_id.value(row)
  50. const asymId = ps.asym_id.value(row)
  51. const seqId = ps.seq_id.value(row)
  52. if (ihm_cross_link_restraint.model_granularity.value(row) === 'by-atom') {
  53. const atomicElement = findAtomIndex(model, entityId, asymId, ps.comp_id.value(row), seqId, ps.atom_id.value(row))
  54. if (atomicElement >= 0) _add(atomicElementMap, atomicElement as ElementIndex, row)
  55. } else if (model.coarseHierarchy.isDefined) {
  56. const sphereElement = model.coarseHierarchy.spheres.findSequenceKey(entityId, asymId, seqId)
  57. if (sphereElement >= 0) {
  58. _add(sphereElementMap, sphereElement, row)
  59. } else {
  60. const gaussianElement = model.coarseHierarchy.gaussians.findSequenceKey(entityId, asymId, seqId)
  61. if (gaussianElement >= 0) _add(gaussianElementMap, gaussianElement, row)
  62. }
  63. }
  64. }
  65. function getMapByKind(kind: Unit.Kind) {
  66. switch (kind) {
  67. case Unit.Kind.Atomic: return atomicElementMap;
  68. case Unit.Kind.Spheres: return sphereElementMap;
  69. case Unit.Kind.Gaussians: return gaussianElementMap;
  70. }
  71. }
  72. /** map from atomic element to cross link indices */
  73. const atomicElementMap: Map<ElementIndex, number[]> = new Map()
  74. /** map from sphere element to cross link indices */
  75. const sphereElementMap: Map<ElementIndex, number[]> = new Map()
  76. /** map from gaussian element to cross link indices */
  77. const gaussianElementMap: Map<ElementIndex, number[]> = new Map()
  78. const emptyIndexArray: number[] = [];
  79. for (let i = 0; i < ihm_cross_link_restraint._rowCount; ++i) {
  80. add(i, p1)
  81. add(i, p2)
  82. }
  83. const crossLinkRestraint = {
  84. getIndicesByElement: (element: ElementIndex, kind: Unit.Kind) => {
  85. const map = getMapByKind(kind)
  86. const idx = map.get(element)
  87. return idx !== undefined ? idx : emptyIndexArray
  88. },
  89. data: ihm_cross_link_restraint
  90. }
  91. model._staticPropertyData[PropName] = crossLinkRestraint
  92. return crossLinkRestraint
  93. }
  94. }