accessible-surface-area.ts 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /**
  2. * Copyright (c) 2019-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { PluginBehavior } from '../../../behavior';
  7. import { ParamDefinition as PD } from '../../../../../mol-util/param-definition';
  8. import { AccessibleSurfaceAreaProvider, AccessibleSurfaceAreaSymbols } from '../../../../../mol-model-props/computed/accessible-surface-area';
  9. import { Loci } from '../../../../../mol-model/loci';
  10. import { AccessibleSurfaceAreaColorThemeProvider } from '../../../../../mol-model-props/computed/themes/accessible-surface-area';
  11. import { OrderedSet } from '../../../../../mol-data/int';
  12. import { arraySum } from '../../../../../mol-util/array';
  13. import { DefaultQueryRuntimeTable } from '../../../../../mol-script/runtime/query/compiler';
  14. import { StructureSelectionQuery, StructureSelectionCategory } from '../../../../../mol-plugin-state/helpers/structure-selection-query';
  15. import { MolScriptBuilder as MS } from '../../../../../mol-script/language/builder';
  16. export const AccessibleSurfaceArea = PluginBehavior.create<{ autoAttach: boolean, showTooltip: boolean }>({
  17. name: 'computed-accessible-surface-area-prop',
  18. category: 'custom-props',
  19. display: { name: 'Accessible Surface Area' },
  20. ctor: class extends PluginBehavior.Handler<{ autoAttach: boolean, showTooltip: boolean }> {
  21. private provider = AccessibleSurfaceAreaProvider
  22. private labelProvider = {
  23. label: (loci: Loci): string | undefined => {
  24. if (!this.params.showTooltip) return;
  25. return accessibleSurfaceAreaLabel(loci);
  26. }
  27. }
  28. update(p: { autoAttach: boolean, showTooltip: boolean }) {
  29. const updated = (
  30. this.params.autoAttach !== p.autoAttach ||
  31. this.params.showTooltip !== p.showTooltip
  32. );
  33. this.params.autoAttach = p.autoAttach;
  34. this.params.showTooltip = p.showTooltip;
  35. this.ctx.customStructureProperties.setDefaultAutoAttach(this.provider.descriptor.name, this.params.autoAttach);
  36. return updated;
  37. }
  38. register(): void {
  39. DefaultQueryRuntimeTable.addCustomProp(this.provider.descriptor);
  40. this.ctx.customStructureProperties.register(this.provider, this.params.autoAttach);
  41. this.ctx.representation.structure.themes.colorThemeRegistry.add(AccessibleSurfaceAreaColorThemeProvider);
  42. this.ctx.managers.lociLabels.addProvider(this.labelProvider);
  43. this.ctx.query.structure.registry.add(isBuried);
  44. this.ctx.query.structure.registry.add(isAccessible);
  45. }
  46. unregister() {
  47. DefaultQueryRuntimeTable.removeCustomProp(this.provider.descriptor);
  48. this.ctx.customStructureProperties.unregister(this.provider.descriptor.name);
  49. this.ctx.representation.structure.themes.colorThemeRegistry.remove(AccessibleSurfaceAreaColorThemeProvider);
  50. this.ctx.managers.lociLabels.removeProvider(this.labelProvider);
  51. this.ctx.query.structure.registry.remove(isBuried);
  52. this.ctx.query.structure.registry.remove(isAccessible);
  53. }
  54. },
  55. params: () => ({
  56. autoAttach: PD.Boolean(false),
  57. showTooltip: PD.Boolean(true)
  58. })
  59. });
  60. //
  61. function accessibleSurfaceAreaLabel(loci: Loci): string | undefined {
  62. if(loci.kind === 'element-loci') {
  63. if (loci.elements.length === 0) return;
  64. const accessibleSurfaceArea = AccessibleSurfaceAreaProvider.get(loci.structure).value;
  65. if (!accessibleSurfaceArea || loci.structure.customPropertyDescriptors.hasReference(AccessibleSurfaceAreaProvider.descriptor)) return;
  66. const { getSerialIndex } = loci.structure.root.serialMapping;
  67. const { area, serialResidueIndex } = accessibleSurfaceArea;
  68. const seen = new Set<number>();
  69. let cummulativeArea = 0;
  70. for (const { indices, unit } of loci.elements) {
  71. const { elements } = unit;
  72. OrderedSet.forEach(indices, idx => {
  73. const rSI = serialResidueIndex[getSerialIndex(unit, elements[idx])];
  74. if (rSI !== -1 && !seen.has(rSI)) {
  75. cummulativeArea += area[rSI];
  76. seen.add(rSI);
  77. }
  78. });
  79. }
  80. if (seen.size === 0) return;
  81. const residueCount = `<small>(${seen.size} ${seen.size > 1 ? 'Residues sum' : 'Residue'})</small>`;
  82. return `Accessible Surface Area ${residueCount}: ${cummulativeArea.toFixed(2)} \u212B<sup>2</sup>`;
  83. } else if(loci.kind === 'structure-loci') {
  84. const accessibleSurfaceArea = AccessibleSurfaceAreaProvider.get(loci.structure).value;
  85. if (!accessibleSurfaceArea || loci.structure.customPropertyDescriptors.hasReference(AccessibleSurfaceAreaProvider.descriptor)) return;
  86. return `Accessible Surface Area <small>(Whole Structure)</small>: ${arraySum(accessibleSurfaceArea.area).toFixed(2)} \u212B<sup>2</sup>`;
  87. }
  88. }
  89. //
  90. const isBuried = StructureSelectionQuery('Buried Protein Residues', MS.struct.modifier.union([
  91. MS.struct.modifier.wholeResidues([
  92. MS.struct.modifier.union([
  93. MS.struct.generator.atomGroups({
  94. 'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']),
  95. 'residue-test': AccessibleSurfaceAreaSymbols.isBuried.symbol(),
  96. })
  97. ])
  98. ])
  99. ]), {
  100. description: 'Select buried protein residues.',
  101. category: StructureSelectionCategory.Residue,
  102. ensureCustomProperties: (ctx, structure) => {
  103. return AccessibleSurfaceAreaProvider.attach(ctx, structure);
  104. }
  105. });
  106. const isAccessible = StructureSelectionQuery('Accessible Protein Residues', MS.struct.modifier.union([
  107. MS.struct.modifier.wholeResidues([
  108. MS.struct.modifier.union([
  109. MS.struct.generator.atomGroups({
  110. 'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']),
  111. 'residue-test': AccessibleSurfaceAreaSymbols.isAccessible.symbol(),
  112. })
  113. ])
  114. ])
  115. ]), {
  116. description: 'Select accessible protein residues.',
  117. category: StructureSelectionCategory.Residue,
  118. ensureCustomProperties: (ctx, structure) => {
  119. return AccessibleSurfaceAreaProvider.attach(ctx, structure);
  120. }
  121. });