Browse Source

queries are now synchronous due to performance reasons

David Sehnal 6 years ago
parent
commit
599ab54063

+ 2 - 2
src/mol-app/ui/visualization/sequence-view.tsx

@@ -34,14 +34,14 @@ function createQuery(entityId: string, label_seq_id: number) {
 // TODO: this is really ineffective and should be done using a canvas.
 class EntitySequence extends React.Component<{ ctx: Context, seq: StructureSequence.Entity, structure: Structure }> {
 
-    async raiseInteractityEvent(seqId?: number) {
+    raiseInteractityEvent(seqId?: number) {
         if (typeof seqId === 'undefined') {
             InteractivityEvents.HighlightLoci.dispatch(this.props.ctx, EmptyLoci);
             return;
         }
 
         const query = createQuery(this.props.seq.entityId, seqId);
-        const loci = StructureSelection.toLoci(await StructureQuery.run(query, this.props.structure));
+        const loci = StructureSelection.toLoci(StructureQuery.run1(query, this.props.structure));
         if (loci.elements.length === 0) InteractivityEvents.HighlightLoci.dispatch(this.props.ctx, EmptyLoci);
         else InteractivityEvents.HighlightLoci.dispatch(this.props.ctx, loci);
     }

+ 1 - 4
src/mol-model/structure/query/context.ts

@@ -4,7 +4,6 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { RuntimeContext } from 'mol-task';
 import { Structure, StructureElement } from '../structure';
 
 export interface QueryContextView {
@@ -17,7 +16,6 @@ export class QueryContext implements QueryContextView {
     private currentLocked = false;
 
     readonly inputStructure: Structure;
-    readonly taskCtx: RuntimeContext;
 
     /** Current element */
     readonly element: StructureElement = StructureElement.create();
@@ -44,9 +42,8 @@ export class QueryContext implements QueryContextView {
         (this.currentStructure as any) = void 0;
     }
 
-    constructor(structure: Structure, taskCtx: RuntimeContext) {
+    constructor(structure: Structure) {
         this.inputStructure = structure;
-        this.taskCtx = taskCtx;
     }
 }
 

+ 32 - 33
src/mol-model/structure/query/queries/filters.ts

@@ -4,38 +4,37 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-// import { StructureQuery } from '../query'
-// import { StructureSelection } from '../selection'
-// import { Unit, StructureProperties as P, Structure } from '../../structure'
-// import { Segmentation, SortedArray } from 'mol-data/int'
-// import { LinearGroupingBuilder } from '../utils/builders';
-// import { QueryPredicate, QueryFn, QueryContextView } from '../context';
+import { SortedArray } from 'mol-data/int';
+import { Structure } from '../../structure';
+import { QueryPredicate } from '../context';
+import { StructureQuery } from '../query';
+import { StructureSelection } from '../selection';
 
-// export function pick(query: StructureQuery, pred: QueryPredicate): StructureQuery {
-//     return async ctx => {
-//         const sel = await query(ctx);
+export function pick(query: StructureQuery, pred: QueryPredicate): StructureQuery {
+    return ctx => {
+        const sel = query(ctx);
 
-//         if (StructureSelection.isSingleton(sel)) {
-//             const ret = StructureSelection.LinearBuilder(ctx.inputStructure);
-//             for (const unit of ctx.inputStructure.units) {
-//                 const { elements } = unit;
-//                 for (let i = 0, _i = elements.length; i < _i; i++) {
-//                     // TODO: optimize this somehow???
-//                     const s = Structure.create([unit.getChild(SortedArray.ofSingleton(elements[i]))]);
-//                     ctx.lockCurrentStructure(s);
-//                     if (pred(ctx)) ret.add(s);
-//                     ctx.unlockCurrentStructure();
-//                 }
-//             }
-//             return ret.getSelection();
-//         } else {
-//             const ret = StructureSelection.LinearBuilder(ctx.inputStructure);
-//             for (const s of sel.structures) {
-//                 ctx.lockCurrentStructure(s);
-//                 if (pred(ctx)) ret.add(s);
-//                 ctx.unlockCurrentStructure();
-//             }
-//             return ret.getSelection();
-//         }
-//     };
-// }
+        if (StructureSelection.isSingleton(sel)) {
+            const ret = StructureSelection.LinearBuilder(ctx.inputStructure);
+            for (const unit of ctx.inputStructure.units) {
+                const { elements } = unit;
+                for (let i = 0, _i = elements.length; i < _i; i++) {
+                    // TODO: optimize this somehow???
+                    const s = Structure.create([unit.getChild(SortedArray.ofSingleton(elements[i]))]);
+                    ctx.lockCurrentStructure(s);
+                    if (pred(ctx)) ret.add(s);
+                    ctx.unlockCurrentStructure();
+                }
+            }
+            return ret.getSelection();
+        } else {
+            const ret = StructureSelection.LinearBuilder(ctx.inputStructure);
+            for (const s of sel.structures) {
+                ctx.lockCurrentStructure(s);
+                if (pred(ctx)) ret.add(s);
+                ctx.unlockCurrentStructure();
+            }
+            return ret.getSelection();
+        }
+    };
+}

+ 4 - 16
src/mol-model/structure/query/queries/generators.ts

@@ -11,7 +11,7 @@ import { Segmentation } from 'mol-data/int'
 import { LinearGroupingBuilder } from '../utils/builders';
 import { QueryPredicate, QueryFn, QueryContextView } from '../context';
 
-export const all: StructureQuery = async (ctx) => StructureSelection.Singletons(ctx.inputStructure, ctx.inputStructure);
+export const all: StructureQuery = ctx => StructureSelection.Singletons(ctx.inputStructure, ctx.inputStructure);
 
 export interface AtomsQueryParams {
     entityTest: QueryPredicate,
@@ -44,13 +44,12 @@ export function atoms(params?: Partial<AtomsQueryParams>): StructureQuery {
 }
 
 function atomGroupsLinear(atomTest: QueryPredicate): StructureQuery {
-    return async (ctx) => {
+    return ctx => {
         const { inputStructure } = ctx;
         const { units } = inputStructure;
         const l = ctx.pushCurrentElement();
         const builder = inputStructure.subsetBuilder(true);
 
-        let progress = 0;
         for (const unit of units) {
             l.unit = unit;
             const elements = unit.elements;
@@ -61,9 +60,6 @@ function atomGroupsLinear(atomTest: QueryPredicate): StructureQuery {
                 if (atomTest(ctx)) builder.addElement(l.element);
             }
             builder.commitUnit();
-
-            progress++;
-            if (ctx.taskCtx.shouldUpdate) await ctx.taskCtx.update({ message: 'Atom Groups', current: progress, max: units.length });
         }
         ctx.popCurrentElement();
         return StructureSelection.Singletons(inputStructure, builder.getStructure());
@@ -71,13 +67,12 @@ function atomGroupsLinear(atomTest: QueryPredicate): StructureQuery {
 }
 
 function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: AtomsQueryParams): StructureQuery {
-    return async (ctx) => {
+    return ctx => {
         const { inputStructure } = ctx;
         const { units } = inputStructure;
         const l = ctx.pushCurrentElement();
         const builder = inputStructure.subsetBuilder(true);
 
-        let progress = 0;
         for (const unit of units) {
             if (unit.kind !== Unit.Kind.Atomic) continue;
 
@@ -110,9 +105,6 @@ function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: A
                 }
             }
             builder.commitUnit();
-
-            progress++;
-            if (ctx.taskCtx.shouldUpdate) await ctx.taskCtx.update({ message: 'Atom Groups', current: progress, max: units.length });
         }
         ctx.popCurrentElement();
         return StructureSelection.Singletons(inputStructure, builder.getStructure());
@@ -120,13 +112,12 @@ function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: A
 }
 
 function atomGroupsGrouped({ entityTest, chainTest, residueTest, atomTest, groupBy }: AtomsQueryParams): StructureQuery {
-    return async (ctx) => {
+    return ctx => {
         const { inputStructure } = ctx;
         const { units } = inputStructure;
         const l = ctx.pushCurrentElement();
         const builder = new LinearGroupingBuilder(inputStructure);
 
-        let progress = 0;
         for (const unit of units) {
             if (unit.kind !== Unit.Kind.Atomic) continue;
 
@@ -155,9 +146,6 @@ function atomGroupsGrouped({ entityTest, chainTest, residueTest, atomTest, group
                     }
                 }
             }
-
-            progress++;
-            if (ctx.taskCtx.shouldUpdate) await ctx.taskCtx.update({ message: 'Atom Groups', current: progress, max: units.length });
         }
         ctx.popCurrentElement();
         return builder.getSelection();

+ 11 - 18
src/mol-model/structure/query/queries/modifiers.ts

@@ -5,14 +5,13 @@
  */
 
 import { Segmentation } from 'mol-data/int';
-import { RuntimeContext } from 'mol-task';
 import { Structure, Unit } from '../../structure';
 import { StructureQuery } from '../query';
 import { StructureSelection } from '../selection';
 import { UniqueStructuresBuilder } from '../utils/builders';
 import { StructureUniqueSubsetBuilder } from '../../structure/util/unique-subset-builder';
 
-function getWholeResidues(ctx: RuntimeContext, source: Structure, structure: Structure) {
+function getWholeResidues(source: Structure, structure: Structure) {
     const builder = source.subsetBuilder(true);
     for (const unit of structure.units) {
         if (unit.kind !== Unit.Kind.Atomic) {
@@ -38,17 +37,14 @@ function getWholeResidues(ctx: RuntimeContext, source: Structure, structure: Str
 }
 
 export function wholeResidues(query: StructureQuery, isFlat: boolean): StructureQuery {
-    return async (ctx) => {
-        const inner = await query(ctx);
+    return ctx => {
+        const inner = query(ctx);
         if (StructureSelection.isSingleton(inner)) {
-            return StructureSelection.Singletons(ctx.inputStructure, getWholeResidues(ctx.taskCtx, ctx.inputStructure, inner.structure));
+            return StructureSelection.Singletons(ctx.inputStructure, getWholeResidues(ctx.inputStructure, inner.structure));
         } else {
             const builder = new UniqueStructuresBuilder(ctx.inputStructure);
-            let progress = 0;
             for (const s of inner.structures) {
-                builder.add(getWholeResidues(ctx.taskCtx, ctx.inputStructure, s));
-                progress++;
-                if (ctx.taskCtx.shouldUpdate) await ctx.taskCtx.update({ message: 'Whole Residues', current: progress, max: inner.structures.length });
+                builder.add(getWholeResidues(ctx.inputStructure, s));
             }
             return builder.getSelection();
         }
@@ -64,12 +60,11 @@ export interface IncludeSurroundingsParams {
     wholeResidues?: boolean
 }
 
-async function getIncludeSurroundings(ctx: RuntimeContext, source: Structure, structure: Structure, params: IncludeSurroundingsParams) {
+function getIncludeSurroundings(source: Structure, structure: Structure, params: IncludeSurroundingsParams) {
     const builder = new StructureUniqueSubsetBuilder(source);
     const lookup = source.lookup3d;
     const r = params.radius;
 
-    let progress = 0;
     for (const unit of structure.units) {
         const { x, y, z } = unit.conformation;
         const elements = unit.elements;
@@ -77,23 +72,21 @@ async function getIncludeSurroundings(ctx: RuntimeContext, source: Structure, st
             const e = elements[i];
             lookup.findIntoBuilder(x(e), y(e), z(e), r, builder);
         }
-        progress++;
-        if (progress % 2500 === 0 && ctx.shouldUpdate) await ctx.update({ message: 'Include Surroudnings', isIndeterminate: true });
     }
-    return !!params.wholeResidues ? getWholeResidues(ctx, source, builder.getStructure()) : builder.getStructure();
+    return !!params.wholeResidues ? getWholeResidues(source, builder.getStructure()) : builder.getStructure();
 }
 
 export function includeSurroundings(query: StructureQuery, params: IncludeSurroundingsParams): StructureQuery {
-    return async (ctx) => {
-        const inner = await query(ctx);
+    return ctx => {
+        const inner = query(ctx);
         if (StructureSelection.isSingleton(inner)) {
-            const surr = await getIncludeSurroundings(ctx.taskCtx, ctx.inputStructure, inner.structure, params);
+            const surr = getIncludeSurroundings(ctx.inputStructure, inner.structure, params);
             const ret = StructureSelection.Singletons(ctx.inputStructure, surr);
             return ret;
         } else {
             const builder = new UniqueStructuresBuilder(ctx.inputStructure);
             for (const s of inner.structures) {
-                builder.add(await getIncludeSurroundings(ctx.taskCtx, ctx.inputStructure, s, params));
+                builder.add(getIncludeSurroundings(ctx.inputStructure, s, params));
             }
             return builder.getSelection();
         }

+ 3 - 8
src/mol-model/structure/query/query.ts

@@ -4,19 +4,14 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { RuntimeContext, Task } from 'mol-task'
 import { Structure } from '../structure'
 import { StructureSelection } from './selection'
 import { QueryContext } from './context';
 
-interface StructureQuery { (ctx: QueryContext): Promise<StructureSelection> }
+interface StructureQuery { (ctx: QueryContext): StructureSelection }
 namespace StructureQuery {
-    export function run(query: StructureQuery, structure: Structure, ctx?: RuntimeContext) {
-        return query(new QueryContext(structure, ctx || RuntimeContext.Synchronous))
-    }
-
-    export function asTask(query: StructureQuery, structure: Structure) {
-        return Task.create('Structure Query', ctx => query(new QueryContext(structure, ctx)));
+    export function run1(query: StructureQuery, structure: Structure) {
+        return query(new QueryContext(structure))
     }
 }
 

+ 2 - 2
src/mol-model/structure/structure/symmetry.ts

@@ -25,10 +25,10 @@ namespace StructureSymmetry {
 
             const assembler = Structure.Builder();
 
-            const queryCtx = new QueryContext(structure, ctx);
+            const queryCtx = new QueryContext(structure);
 
             for (const g of assembly.operatorGroups) {
-                const selection = await g.selector(queryCtx);
+                const selection = g.selector(queryCtx);
                 if (StructureSelection.structureCount(selection) === 0) {
                     continue;
                 }

+ 7 - 7
src/perf-tests/structure.ts

@@ -331,7 +331,7 @@ export namespace PropertyAccess {
             radius: 5,
             wholeResidues: true
         });
-        const surr = StructureSelection.unionStructure(await StructureQuery.run(q1, a));
+        const surr = StructureSelection.unionStructure(StructureQuery.run1(q1, a));
         console.timeEnd('symmetry')
 
         // for (const u of surr.units) {
@@ -372,7 +372,7 @@ export namespace PropertyAccess {
     // }
 
     function query(q: StructureQuery, s: Structure) {
-        return StructureQuery.run(q, s);
+        return StructureQuery.run1(q, s);
     }
 
     export async function run() {
@@ -444,13 +444,13 @@ export namespace PropertyAccess {
         //console.log(to_mmCIF('test', Selection.union(q0r)));
 
         console.time('q1')
-        await query(q1, structures[0]);
+        query(q1, structures[0]);
         console.timeEnd('q1')
         console.time('q1')
-        await query(q1, structures[0]);
+        query(q1, structures[0]);
         console.timeEnd('q1')
         console.time('q2')
-        const q2r = await query(q2, structures[0]);
+        const q2r = query(q2, structures[0]);
         console.timeEnd('q2')
         console.log(StructureSelection.structureCount(q2r));
         //console.log(q1(structures[0]));
@@ -461,8 +461,8 @@ export namespace PropertyAccess {
             //.add('test q', () => q1(structures[0]))
             //.add('test q', () => q(structures[0]))
             .add('test int', () => sumProperty(structures[0], l => col(l.element)))
-            .add('test q1', async () => await query(q1, structures[0]))
-            .add('test q3', async () => await query(q3, structures[0]))
+            .add('test q1', async () => query(q1, structures[0]))
+            .add('test q3', async () => query(q3, structures[0]))
             // .add('sum residue', () => sumPropertyResidue(structures[0], l => l.unit.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.atom])))
 
             // .add('baseline', () =>  baseline(models[0]))

+ 1 - 1
src/servers/model/server/query.ts

@@ -69,7 +69,7 @@ export async function resolveRequest(req: Request, writer: Writer) {
         ? await req.queryDefinition.structureTransform(req.normalizedParams, wrappedStructure.structure)
         : wrappedStructure.structure;
     const query = req.queryDefinition.query(req.normalizedParams, structure);
-    const result = StructureSelection.unionStructure(await StructureQuery.asTask(query, structure).run(abortingObserver, 250));
+    const result = StructureSelection.unionStructure(StructureQuery.run1(query, structure));
     perf.end('query');
 
     ConsoleLogger.logId(req.id, 'Query', 'Query finished.');