atomic-keys.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. /**
  2. * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import { AtomicData, AtomicSegments, AtomicKeys } from '../atomic'
  7. import { Interval, Segmentation } from 'mol-data/int'
  8. import { Entities } from '../common'
  9. function getResidueId(comp_id: string, seq_id: number, ins_code: string) {
  10. return `${comp_id} ${seq_id} ${ins_code}`;
  11. }
  12. function getElementKey(map: Map<string, number>, key: string, counter: { index: number }) {
  13. if (map.has(key)) return map.get(key)!;
  14. const ret = counter.index++;
  15. map.set(key, ret);
  16. return ret;
  17. }
  18. function getElementSubstructureKeyMap(map: Map<number, Map<string, number>>, key: number) {
  19. if (map.has(key)) return map.get(key)!;
  20. const ret = new Map<string, number>();
  21. map.set(key, ret);
  22. return ret;
  23. }
  24. function createLookUp(entities: Entities, chain: Map<number, Map<string, number>>, residue: Map<number, Map<string, number>>) {
  25. const getEntKey = entities.getEntityIndex;
  26. const findChainKey: AtomicKeys['findChainKey'] = (e, c) => {
  27. let eKey = getEntKey(e);
  28. if (eKey < 0) return -1;
  29. const cm = chain.get(eKey)!;
  30. if (!cm.has(c)) return -1;
  31. return cm.get(c)!;
  32. }
  33. const findResidueKey: AtomicKeys['findResidueKey'] = (e, c, name, seq, ins) => {
  34. let eKey = getEntKey(e);
  35. if (eKey < 0) return -1;
  36. const cm = chain.get(eKey)!;
  37. if (!cm.has(c)) return -1;
  38. const rm = residue.get(cm.get(c)!)!
  39. const id = getResidueId(name, seq, ins);
  40. if (!rm.has(id)) return -1;
  41. return rm.get(id)!;
  42. }
  43. return { findChainKey, findResidueKey };
  44. }
  45. function checkMonotonous(xs: ArrayLike<number>) {
  46. for (let i = 1, _i = xs.length; i < _i; i++) {
  47. if (xs[i] < xs[i - 1]) {
  48. return false;
  49. }
  50. }
  51. return true;
  52. }
  53. function missingEntity(k: string) {
  54. throw new Error(`Missing entity entry for entity id '${k}'.`);
  55. }
  56. export function getAtomicKeys(data: AtomicData, entities: Entities, segments: AtomicSegments): AtomicKeys {
  57. const { chains, residues } = data;
  58. const chainMaps = new Map<number, Map<string, number>>(), chainCounter = { index: 0 };
  59. const residueMaps = new Map<number, Map<string, number>>(), residueCounter = { index: 0 };
  60. const residueKey = new Int32Array(residues._rowCount);
  61. const chainKey = new Int32Array(chains._rowCount);
  62. const entityKey = new Int32Array(chains._rowCount);
  63. const { label_comp_id, auth_seq_id, pdbx_PDB_ins_code } = data.residues;
  64. const { label_entity_id, label_asym_id } = data.chains;
  65. const atomSet = Interval.ofBounds(0, data.atoms._rowCount);
  66. let isMonotonous = true;
  67. const chainsIt = Segmentation.transientSegments(segments.chainSegments, atomSet);
  68. while (chainsIt.hasNext) {
  69. const chainSegment = chainsIt.move();
  70. const cI = chainSegment.index;
  71. let eKey = entities.getEntityIndex(label_entity_id.value(cI));
  72. if (eKey < 0) missingEntity(label_entity_id.value(cI));
  73. const chainMap = getElementSubstructureKeyMap(chainMaps, eKey);
  74. const cKey = getElementKey(chainMap, label_asym_id.value(cI), chainCounter);
  75. chainKey[cI] = cKey;
  76. entityKey[cI] = eKey;
  77. const residueMap = getElementSubstructureKeyMap(residueMaps, cKey);
  78. const residuesIt = Segmentation.transientSegments(segments.residueSegments, atomSet, chainSegment);
  79. let last_seq_id = Number.NEGATIVE_INFINITY;
  80. while (residuesIt.hasNext) {
  81. const residueSegment = residuesIt.move();
  82. const rI = residueSegment.index;
  83. const seq_id = auth_seq_id.value(rI);
  84. if (seq_id < last_seq_id) isMonotonous = false;
  85. last_seq_id = seq_id;
  86. const residueId = getResidueId(label_comp_id.value(rI), auth_seq_id.value(rI), pdbx_PDB_ins_code.value(rI));
  87. residueKey[rI] = getElementKey(residueMap, residueId, residueCounter);
  88. }
  89. }
  90. const { findChainKey, findResidueKey } = createLookUp(entities, chainMaps, residueMaps);
  91. return {
  92. isMonotonous: isMonotonous && checkMonotonous(entityKey) && checkMonotonous(chainKey) && checkMonotonous(residueKey),
  93. residueKey: residueKey,
  94. chainKey: chainKey,
  95. entityKey: entityKey,
  96. findChainKey,
  97. findResidueKey
  98. };
  99. }