secondary-structure.ts 6.7 KB

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