Procházet zdrojové kódy

StructureSelectionQuery improvements

- delayed query compilation to work with CustomPropSymbol
- optional async ensureCustomProperties method
- added hasClash, isBuried, isAccessible built-ins
- integrate .ensureCustomProperties with StructureSelectionHelper
Alexander Rose před 5 roky
rodič
revize
69c73f3dcd

+ 14 - 8
src/mol-plugin-ui/structure/selection.tsx

@@ -7,13 +7,13 @@
 
 import * as React from 'react';
 import { CollapsableControls, CollapsableState } from '../base';
-import { StructureSelectionQueries, SelectionModifier } from '../../mol-plugin/util/structure-selection-helper';
+import { StructureSelectionQueries, StructureSelectionQuery, SelectionModifier } from '../../mol-plugin/util/structure-selection-helper';
 import { PluginCommands } from '../../mol-plugin/command';
 import { ParamDefinition as PD } from '../../mol-util/param-definition';
 import { Interactivity } from '../../mol-plugin/util/interactivity';
 import { ParameterControls } from '../controls/parameters';
 import { stripTags, stringToWords } from '../../mol-util/string';
-import { StructureElement, StructureQuery, StructureSelection } from '../../mol-model/structure';
+import { StructureElement, StructureSelection } from '../../mol-model/structure';
 import { ActionMenu } from '../controls/action-menu';
 import { compile } from '../../mol-script/runtime/query/compiler';
 import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
@@ -21,7 +21,7 @@ import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
 const SSQ = StructureSelectionQueries
 
 function SSQItem(name: keyof typeof SSQ) {
-    return ActionMenu.Item(SSQ[name].label, SSQ[name].query)
+    return ActionMenu.Item(SSQ[name].label, SSQ[name])
 }
 
 const StandardAminoAcids = [
@@ -89,6 +89,8 @@ const DefaultQueries = [
     ],
     [
         'Amino Acids',
+        SSQItem('isBuried'),
+        SSQItem('isAccessible'),
         ...StandardAminoAcids.map(v => ResidueItem(v)),
     ],
     [
@@ -100,6 +102,10 @@ const DefaultQueries = [
         SSQItem('surroundings'),
         SSQItem('complement'),
         SSQItem('bonded'),
+    ],
+    [
+        'Validation',
+        SSQItem('hasClash'),
     ]
 ] as unknown as ActionMenu.Spec
 
@@ -197,13 +203,13 @@ export class StructureSelectionControls<P, S extends StructureSelectionControlsS
         }
     }
 
-    set = (modifier: SelectionModifier, query: StructureQuery) => {
-        this.plugin.helpers.structureSelection.set(modifier, query, false)
+    set = (modifier: SelectionModifier, selectionQuery: StructureSelectionQuery) => {
+        this.plugin.helpers.structureSelection.set(modifier, selectionQuery, false)
     }
 
-    add = (value: StructureQuery) => this.set('add', value)
-    remove = (value: StructureQuery) => this.set('remove', value)
-    only = (value: StructureQuery) => this.set('only', value)
+    add = (value: StructureSelectionQuery) => this.set('add', value)
+    remove = (value: StructureSelectionQuery) => this.set('remove', value)
+    only = (value: StructureSelectionQuery) => this.set('only', value)
 
     queries = DefaultQueries
 

+ 83 - 18
src/mol-plugin/util/structure-selection-helper.ts

@@ -8,7 +8,7 @@
 import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
 import { StateSelection, StateBuilder } from '../../mol-state';
 import { PluginStateObject } from '../state/objects';
-import { QueryContext, StructureSelection, StructureQuery, StructureElement } from '../../mol-model/structure';
+import { QueryContext, StructureSelection, StructureQuery, StructureElement, Structure } from '../../mol-model/structure';
 import { compile } from '../../mol-script/runtime/query/compiler';
 import { Loci } from '../../mol-model/loci';
 import { PluginContext } from '../context';
@@ -16,16 +16,31 @@ import Expression from '../../mol-script/language/expression';
 import { BondType, ProteinBackboneAtoms, NucleicBackboneAtoms, SecondaryStructureType } from '../../mol-model/structure/model/types';
 import { StateTransforms } from '../state/transforms';
 import { SetUtils } from '../../mol-util/set';
+import { ValidationReport, ValidationReportProvider } from '../../mol-model-props/rcsb/validation-report';
+import { CustomProperty } from '../../mol-model-props/common/custom-property';
+import { Task } from '../../mol-task';
+import { AccessibleSurfaceAreaSymbols, AccessibleSurfaceAreaProvider } from '../../mol-model-props/computed/accessible-surface-area';
 
 export interface StructureSelectionQuery {
-    label: string
-    query: StructureQuery
-    expression: Expression
-    description: string
+    readonly label: string
+    readonly expression: Expression
+    readonly description: string
+    readonly query: StructureQuery
+    readonly ensureCustomProperties?: (ctx: CustomProperty.Context, structure: Structure) => Promise<void>
 }
 
-export function StructureSelectionQuery(label: string, expression: Expression, description = ''): StructureSelectionQuery {
-    return { label, expression, query: compile<StructureSelection>(expression), description }
+export function StructureSelectionQuery(label: string, expression: Expression, description = '', ensureCustomProperties?: (ctx: CustomProperty.Context, structure: Structure) => Promise<void>): StructureSelectionQuery {
+    let _query: StructureQuery
+    return {
+        label,
+        expression,
+        description,
+        get query() {
+            if (!_query) _query = compile<StructureSelection>(expression)
+            return _query
+        },
+        ensureCustomProperties
+    }
 }
 
 const all = StructureSelectionQuery('All', MS.struct.generator.all())
@@ -320,6 +335,45 @@ const bonded = StructureSelectionQuery('Residues Bonded to Selection', MS.struct
     })
 ]), 'Select residues covalently bonded to current selection.')
 
+const hasClash = StructureSelectionQuery('Residues with Clashes', MS.struct.modifier.union([
+    MS.struct.modifier.wholeResidues([
+        MS.struct.modifier.union([
+            MS.struct.generator.atomGroups({
+                'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']),
+                'atom-test': ValidationReport.symbols.hasClash.symbol(),
+            })
+        ])
+    ])
+]), 'Select residues with clashes in the wwPDB validation report.', (ctx, structure) => {
+    return ValidationReportProvider.attach(ctx, structure.models[0])
+})
+
+const isBuried = StructureSelectionQuery('Buried Protein Residues', MS.struct.modifier.union([
+    MS.struct.modifier.wholeResidues([
+        MS.struct.modifier.union([
+            MS.struct.generator.atomGroups({
+                'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']),
+                'residue-test': AccessibleSurfaceAreaSymbols.isBuried.symbol(),
+            })
+        ])
+    ])
+]), 'Select buried protein residues.', (ctx, structure) => {
+    return AccessibleSurfaceAreaProvider.attach(ctx, structure)
+})
+
+const isAccessible = StructureSelectionQuery('Accessible Protein Residues', MS.struct.modifier.union([
+    MS.struct.modifier.wholeResidues([
+        MS.struct.modifier.union([
+            MS.struct.generator.atomGroups({
+                'chain-test': MS.core.rel.eq([MS.ammp('objectPrimitive'), 'atomistic']),
+                'residue-test': AccessibleSurfaceAreaSymbols.isAccessible.symbol(),
+            })
+        ])
+    ])
+]), 'Select accessible protein residues.', (ctx, structure) => {
+    return AccessibleSurfaceAreaProvider.attach(ctx, structure)
+})
+
 export const StructureSelectionQueries = {
     all,
     polymer,
@@ -346,6 +400,10 @@ export const StructureSelectionQueries = {
     surroundings,
     complement,
     bonded,
+
+    hasClash,
+    isBuried,
+    isAccessible
 }
 
 export function applyBuiltInSelection(to: StateBuilder.To<PluginStateObject.Molecule.Structure>, query: keyof typeof StructureSelectionQueries, customTag?: string) {
@@ -377,17 +435,24 @@ export class StructureSelectionHelper {
         }
     }
 
-    set(modifier: SelectionModifier, query: StructureQuery, applyGranularity = true) {
-        for (const s of this.structures) {
-            const current = this.plugin.helpers.structureSelectionManager.get(s)
-            const currentSelection = Loci.isEmpty(current)
-                ? StructureSelection.Empty(s)
-                : StructureSelection.Singletons(s, StructureElement.Loci.toStructure(current))
-
-            const result = query(new QueryContext(s, { currentSelection }))
-            const loci = StructureSelection.toLociWithSourceUnits(result)
-            this._set(modifier, loci, applyGranularity)
-        }
+    async set(modifier: SelectionModifier, selectionQuery: StructureSelectionQuery, applyGranularity = true) {
+        this.plugin.runTask(Task.create('Structure Selection', async runtime => {
+            const ctx = { fetch: this.plugin.fetch, runtime }
+            for (const s of this.structures) {
+                const current = this.plugin.helpers.structureSelectionManager.get(s)
+                const currentSelection = Loci.isEmpty(current)
+                    ? StructureSelection.Empty(s)
+                    : StructureSelection.Singletons(s, StructureElement.Loci.toStructure(current))
+
+                if (selectionQuery.ensureCustomProperties) {
+                    await selectionQuery.ensureCustomProperties(ctx, s)
+                }
+
+                const result = selectionQuery.query(new QueryContext(s, { currentSelection }))
+                const loci = StructureSelection.toLociWithSourceUnits(result)
+                this._set(modifier, loci, applyGranularity)
+            }
+        }))
     }
 
     constructor(private plugin: PluginContext) {