secondary-structure.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /**
  2. * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  6. */
  7. import { mmCIF_Database as mmCIF, mmCIF_Database } from '../../../mol-io/reader/cif/schema/mmcif'
  8. import { SecondaryStructureType } from '../../../mol-model/structure/model/types';
  9. import { AtomicHierarchy } from '../../../mol-model/structure/model/properties/atomic';
  10. import { SecondaryStructure } from '../../../mol-model/structure/model/properties/seconday-structure';
  11. import { Column } from '../../../mol-data/db';
  12. import { ChainIndex, ResidueIndex } from '../../../mol-model/structure/model/indexing';
  13. export function getSecondaryStructure(data: mmCIF_Database, hierarchy: AtomicHierarchy): SecondaryStructure {
  14. const map: SecondaryStructureMap = new Map();
  15. const elements: SecondaryStructure.Element[] = [{ kind: 'none' }];
  16. addHelices(data.struct_conf, map, elements);
  17. // must add Helices 1st because of 'key' value assignment.
  18. addSheets(data.struct_sheet_range, map, data.struct_conf._rowCount, elements);
  19. const n = hierarchy.residues._rowCount
  20. const getIndex = (rI: ResidueIndex) => rI
  21. const secStruct: SecondaryStructureData = {
  22. type: new Int32Array(n) as any,
  23. key: new Int32Array(n) as any,
  24. elements
  25. };
  26. if (map.size > 0) assignSecondaryStructureRanges(hierarchy, map, secStruct);
  27. return SecondaryStructure(secStruct.type, secStruct.key, secStruct.elements, getIndex);
  28. }
  29. type SecondaryStructureEntry = {
  30. startSeqNumber: number,
  31. startInsCode: string | null,
  32. endSeqNumber: number,
  33. endInsCode: string | null,
  34. type: SecondaryStructureType,
  35. key: number
  36. }
  37. type SecondaryStructureMap = Map<string, Map<number, SecondaryStructureEntry[]>>
  38. type SecondaryStructureData = { type: SecondaryStructureType[], key: number[], elements: SecondaryStructure.Element[] }
  39. function addHelices(cat: mmCIF['struct_conf'], map: SecondaryStructureMap, elements: SecondaryStructure.Element[]) {
  40. if (!cat._rowCount) return;
  41. const { beg_label_asym_id, beg_label_seq_id, pdbx_beg_PDB_ins_code } = cat;
  42. const { end_label_seq_id, pdbx_end_PDB_ins_code } = cat;
  43. const { pdbx_PDB_helix_class, conf_type_id, details } = cat;
  44. for (let i = 0, _i = cat._rowCount; i < _i; i++) {
  45. const type = SecondaryStructureType.create(pdbx_PDB_helix_class.valueKind(i) === Column.ValueKind.Present
  46. ? SecondaryStructureType.SecondaryStructurePdb[pdbx_PDB_helix_class.value(i)]
  47. : conf_type_id.valueKind(i) === Column.ValueKind.Present
  48. ? SecondaryStructureType.SecondaryStructureMmcif[conf_type_id.value(i)]
  49. : SecondaryStructureType.Flag.NA);
  50. const element: SecondaryStructure.Helix = {
  51. kind: 'helix',
  52. flags: type,
  53. type_id: conf_type_id.valueKind(i) === Column.ValueKind.Present ? conf_type_id.value(i) : 'HELIX_P',
  54. helix_class: pdbx_PDB_helix_class.value(i),
  55. details: details.valueKind(i) === Column.ValueKind.Present ? details.value(i) : void 0
  56. };
  57. const entry: SecondaryStructureEntry = {
  58. startSeqNumber: beg_label_seq_id.value(i),
  59. startInsCode: pdbx_beg_PDB_ins_code.value(i),
  60. endSeqNumber: end_label_seq_id.value(i),
  61. endInsCode: pdbx_end_PDB_ins_code.value(i),
  62. type,
  63. key: elements.length
  64. };
  65. elements[elements.length] = element;
  66. const asymId = beg_label_asym_id.value(i)!;
  67. if (map.has(asymId)) {
  68. const entries = map.get(asymId)!
  69. if (entries.has(entry.startSeqNumber)) {
  70. entries.get(entry.startSeqNumber)!.push(entry)
  71. } else {
  72. entries.set(entry.startSeqNumber, [entry]);
  73. }
  74. } else {
  75. map.set(asymId, new Map([[entry.startSeqNumber, [entry]]]));
  76. }
  77. }
  78. }
  79. function addSheets(cat: mmCIF['struct_sheet_range'], map: SecondaryStructureMap, sheetCount: number, elements: SecondaryStructure.Element[]) {
  80. if (!cat._rowCount) return;
  81. const { beg_label_asym_id, beg_label_seq_id, pdbx_beg_PDB_ins_code } = cat;
  82. const { end_label_seq_id, pdbx_end_PDB_ins_code } = cat;
  83. const { sheet_id } = cat;
  84. const sheet_id_key = new Map<string, number>();
  85. let currentKey = sheetCount + 1;
  86. for (let i = 0, _i = cat._rowCount; i < _i; i++) {
  87. const id = sheet_id.value(i);
  88. let key: number;
  89. if (sheet_id_key.has(id)) key = sheet_id_key.get(id)!;
  90. else {
  91. key = currentKey++;
  92. sheet_id_key.set(id, key);
  93. }
  94. const type = SecondaryStructureType.create(SecondaryStructureType.Flag.Beta | SecondaryStructureType.Flag.BetaSheet);
  95. const element: SecondaryStructure.Sheet = {
  96. kind: 'sheet',
  97. flags: type,
  98. sheet_id: id,
  99. symmetry: void 0
  100. }
  101. const entry: SecondaryStructureEntry = {
  102. startSeqNumber: beg_label_seq_id.value(i),
  103. startInsCode: pdbx_beg_PDB_ins_code.value(i),
  104. endSeqNumber: end_label_seq_id.value(i),
  105. endInsCode: pdbx_end_PDB_ins_code.value(i),
  106. type,
  107. key: elements.length
  108. };
  109. elements[elements.length] = element;
  110. const asymId = beg_label_asym_id.value(i)!;
  111. if (map.has(asymId)) {
  112. const entries = map.get(asymId)!
  113. if (entries.has(entry.startSeqNumber)) {
  114. entries.get(entry.startSeqNumber)!.push(entry)
  115. } else {
  116. entries.set(entry.startSeqNumber, [entry]);
  117. }
  118. } else {
  119. map.set(asymId, new Map([[entry.startSeqNumber, [entry]]]));
  120. }
  121. }
  122. return;
  123. }
  124. function assignSecondaryStructureEntry(hierarchy: AtomicHierarchy, entry: SecondaryStructureEntry, resStart: ResidueIndex, resEnd: ResidueIndex, data: SecondaryStructureData) {
  125. const { label_seq_id, pdbx_PDB_ins_code } = hierarchy.residues;
  126. const { endSeqNumber, endInsCode, key, type } = entry;
  127. let rI = resStart;
  128. while (rI < resEnd) {
  129. const seqNumber = label_seq_id.value(rI);
  130. data.type[rI] = type;
  131. data.key[rI] = key;
  132. if ((seqNumber > endSeqNumber) ||
  133. (seqNumber === endSeqNumber && pdbx_PDB_ins_code.value(rI) === endInsCode)) {
  134. break;
  135. }
  136. rI++;
  137. }
  138. }
  139. function assignSecondaryStructureRanges(hierarchy: AtomicHierarchy, map: SecondaryStructureMap, data: SecondaryStructureData) {
  140. const { count: chainCount } = hierarchy.chainAtomSegments;
  141. const { label_asym_id } = hierarchy.chains;
  142. const { label_seq_id, pdbx_PDB_ins_code } = hierarchy.residues;
  143. for (let cI = 0 as ChainIndex; cI < chainCount; cI++) {
  144. const resStart = AtomicHierarchy.chainStartResidueIndex(hierarchy, cI), resEnd = AtomicHierarchy.chainEndResidueIndexExcl(hierarchy, cI);
  145. const asymId = label_asym_id.value(cI);
  146. if (map.has(asymId)) {
  147. const entries = map.get(asymId)!;
  148. for (let rI = resStart; rI < resEnd; rI++) {
  149. const seqNumber = label_seq_id.value(rI);
  150. if (entries.has(seqNumber)) {
  151. const entryList = entries.get(seqNumber)!;
  152. for (const entry of entryList) {
  153. const insCode = pdbx_PDB_ins_code.value(rI);
  154. if (entry.startInsCode !== insCode) continue;
  155. assignSecondaryStructureEntry(hierarchy, entry, rI, resEnd, data);
  156. }
  157. }
  158. }
  159. }
  160. }
  161. }