hierarchy-keys.ts 4.5 KB

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