symmetry.ts 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. /**
  2. * Copyright (C) 2022, Protein Bioinformatics Research Group, RCNS
  3. *
  4. * Licensed under CC BY-NC 4.0, see LICENSE file for more info.
  5. *
  6. * @author Gabor Tusnady <tusnady.gabor@ttk.hu>
  7. * @author Csongor Gerdan <gerdan.csongor@ttk.hu>
  8. */
  9. import { MmcifFormat } from '../../mol-model-formats/structure/mmcif';
  10. import { Column, Table } from '../../mol-data/db';
  11. import { mmCIF_Schema } from '../../mol-io/reader/cif/schema/mmcif';
  12. import { Model } from '../../mol-model/structure';
  13. import { ModelSymmetry } from '../../mol-model-formats/structure/property/symmetry';
  14. import { PDBTMDescriptor } from './types';
  15. import { DebugUtil } from './debug-utils';
  16. export function registerTmDetSymmetry(pdbtmDescriptor: PDBTMDescriptor) {
  17. ModelSymmetry.Provider.formatRegistry.remove('mmCIF');
  18. const excludedChains = constructChainListFromOperations(pdbtmDescriptor);
  19. ModelSymmetry.Provider.formatRegistry.add('mmCIF', function(model: Model) {
  20. return tmDetSymmetryFromMmCif(model, excludedChains);
  21. });
  22. }
  23. function constructChainListFromOperations(pdbtmDescriptor: PDBTMDescriptor): string[] {
  24. const excludedChains: string[] = [];
  25. // add chain deletes
  26. const biomatrix = pdbtmDescriptor.additional_entry_annotations.biomatrix;
  27. if (biomatrix?.chain_deletes) {
  28. biomatrix.chain_deletes.forEach(
  29. chainId => excludedChains.push(chainId)
  30. );
  31. }
  32. // exclude result of transformations
  33. if (biomatrix?.matrix_list) {
  34. biomatrix.matrix_list.forEach(
  35. matrix => matrix.apply_to_chain_list.forEach(
  36. applyItem => excludedChains.push(applyItem.new_chain_id)
  37. )
  38. );
  39. }
  40. return excludedChains;
  41. }
  42. function tmDetSymmetryFromMmCif(model: Model, excludedChains: string[]) {
  43. if (!MmcifFormat.is(model.sourceData)) return;
  44. let data = model.sourceData.data.db;
  45. excludedChains = union(
  46. excludedChains,
  47. Array.from(data.pdbx_nonpoly_scheme.asym_id.toArray())
  48. );
  49. const updated_pdbx_struct_assembly_gen = createPdbxStructAssemblyGen(
  50. data.pdbx_struct_assembly_gen,
  51. excludedChains
  52. );
  53. DebugUtil.log('Non-poly entities:', Table.formatToString(data.pdbx_entity_nonpoly));
  54. DebugUtil.log('Non-poly chains:', data.pdbx_nonpoly_scheme.asym_id.toArray());
  55. const only_identity_operation = createPdbxStructOperList(data.pdbx_struct_oper_list);
  56. return ModelSymmetry.fromData({
  57. symmetry: data.symmetry,
  58. cell: data.cell,
  59. struct_ncs_oper: data.struct_ncs_oper,
  60. atom_sites: data.atom_sites,
  61. pdbx_struct_assembly: data.pdbx_struct_assembly,
  62. pdbx_struct_assembly_gen: updated_pdbx_struct_assembly_gen,
  63. pdbx_struct_oper_list: only_identity_operation
  64. });
  65. }
  66. function createPdbxStructAssemblyGen(pdbx_struct_assembly_gen: Table<mmCIF_Schema['pdbx_struct_assembly_gen']>,
  67. excludedChains: string[]): Table<mmCIF_Schema['pdbx_struct_assembly_gen']> {
  68. const asym_id_list_column = createAsymIdColumn(
  69. pdbx_struct_assembly_gen, excludedChains
  70. );
  71. // create table with new column
  72. let updated_pdbx_struct_assembly_gen = Table.ofColumns(
  73. pdbx_struct_assembly_gen._schema,
  74. {
  75. assembly_id: Column.ofStringArray([ '1' ]),
  76. asym_id_list: asym_id_list_column,
  77. //oper_expression: data.pdbx_struct_assembly_gen.oper_expression
  78. // NOTE: we expect here pdbx_struct_assembly_gen has only one row
  79. oper_expression: Column.ofStringArray([ '1' ])
  80. }
  81. );
  82. DebugUtil.log('Orig. assembly_gen', Table.formatToString(pdbx_struct_assembly_gen));
  83. DebugUtil.log('Updated assembly_gen', Table.formatToString(updated_pdbx_struct_assembly_gen));
  84. return updated_pdbx_struct_assembly_gen;
  85. }
  86. function createPdbxStructOperList(pdbx_struct_oper_list: Table<mmCIF_Schema['pdbx_struct_oper_list']>):
  87. Table<mmCIF_Schema['pdbx_struct_oper_list']> {
  88. let updated_pdbx_struct_oper_list = Table.ofColumns(
  89. pdbx_struct_oper_list._schema,
  90. {
  91. id: Column.ofStringArray([ '1' ]),
  92. type: Column.ofArray({
  93. array: [ 'identity operation' ],
  94. schema: pdbx_struct_oper_list.type.schema
  95. }),
  96. name: Column.ofStringArray([ '1_555' ]),
  97. symmetry_operation: Column.ofStringArray([ 'x,y,z' ]),
  98. matrix: Column.ofArray({
  99. array: [[ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]],
  100. schema: pdbx_struct_oper_list.matrix.schema
  101. }),
  102. vector: Column.ofArray({
  103. array: [ [ 0, 0, 0 ] ],
  104. schema: pdbx_struct_oper_list.vector.schema
  105. })
  106. }
  107. );
  108. DebugUtil.log('Orig. pdbx_struct_oper_list', Table.formatToString(pdbx_struct_oper_list));
  109. DebugUtil.log('Updated pdbx_struct_oper_list', Table.formatToString(updated_pdbx_struct_oper_list));
  110. return updated_pdbx_struct_oper_list;
  111. }
  112. function createAsymIdColumn(pdbx_struct_assembly_gen: Table<mmCIF_Schema['pdbx_struct_assembly_gen']>,
  113. excludedChains: string[]) {
  114. let asym_id_list: string[] = [];
  115. for (let i = 0; i < pdbx_struct_assembly_gen._rowCount; i++) {
  116. const currentAsymIdList = pdbx_struct_assembly_gen.asym_id_list.value(i);
  117. asym_id_list = asym_id_list.concat(currentAsymIdList);
  118. }
  119. asym_id_list = minus(asym_id_list, excludedChains);
  120. DebugUtil.log('Excluded chains:', excludedChains);
  121. DebugUtil.log('Included chains:', asym_id_list);
  122. return Column.ofStringListArray([ asym_id_list ]);
  123. }
  124. // difference of two string arrays (interpreted as sets)
  125. function minus(a: string[], b: string[]): string[] {
  126. const b_set = new Set(b);
  127. const difference = a.filter(x => !b_set.has(x));
  128. return Array.from(new Set(difference).values());
  129. }
  130. // union of two string arrays (interpreted as sets)
  131. function union(a: string[], b: string[]): string[] {
  132. const a_set = new Set(a);
  133. b.forEach(item => a_set.add(item));
  134. return Array.from(a_set.values());
  135. }