diff --git a/src/mol-app/ui/visualization/sequence-view.tsx b/src/mol-app/ui/visualization/sequence-view.tsx index 6025eea22076a5e71ed57bc3c2d5be2ded4be068..69a88950239c43d2f3584337264af20a39d8a24e 100644 --- a/src/mol-app/ui/visualization/sequence-view.tsx +++ b/src/mol-app/ui/visualization/sequence-view.tsx @@ -7,10 +7,9 @@ import * as React from 'react' import { View } from '../view'; import { SequenceViewController } from '../../controller/visualization/sequence-view'; -import { Structure, StructureSequence, Queries, Selection, StructureProperties } from 'mol-model/structure'; +import { Structure, StructureSequence, Queries, StructureSelection, StructureProperties, StructureQuery } from 'mol-model/structure'; import { Context } from '../../context/context'; import { InteractivityEvents } from '../../event/basic'; -import { SyncRuntimeContext } from 'mol-task/execution/synchronous'; import { EmptyLoci } from 'mol-model/loci'; export class SequenceView extends View<SequenceViewController, {}, {}> { @@ -27,8 +26,8 @@ export class SequenceView extends View<SequenceViewController, {}, {}> { function createQuery(entityId: string, label_seq_id: number) { return Queries.generators.atoms({ - entityTest: l => StructureProperties.entity.id(l) === entityId, - residueTest: l => StructureProperties.residue.label_seq_id(l) === label_seq_id + entityTest: ctx => StructureProperties.entity.id(ctx.element) === entityId, + residueTest: ctx => StructureProperties.residue.label_seq_id(ctx.element) === label_seq_id }); } @@ -42,7 +41,7 @@ class EntitySequence extends React.Component<{ ctx: Context, seq: StructureSeque } const query = createQuery(this.props.seq.entityId, seqId); - const loci = Selection.toLoci(await query(this.props.structure, SyncRuntimeContext)); + const loci = StructureSelection.toLoci(await StructureQuery.run(query, this.props.structure)); if (loci.elements.length === 0) InteractivityEvents.HighlightLoci.dispatch(this.props.ctx, EmptyLoci); else InteractivityEvents.HighlightLoci.dispatch(this.props.ctx, loci); } diff --git a/src/mol-model/structure/model/formats/mmcif/assembly.ts b/src/mol-model/structure/model/formats/mmcif/assembly.ts index c86abd27cfd5b2d3a156268cc3ed5967e7639160..e89690e1723ca31eca3c7295114331e97c9c786a 100644 --- a/src/mol-model/structure/model/formats/mmcif/assembly.ts +++ b/src/mol-model/structure/model/formats/mmcif/assembly.ts @@ -8,7 +8,7 @@ import { Mat4, Tensor } from 'mol-math/linear-algebra' import { SymmetryOperator } from 'mol-math/geometry/symmetry-operator' import Format from '../../format' import { Assembly, OperatorGroup, OperatorGroups } from '../../properties/symmetry' -import { Queries as Q, Query } from '../../../query' +import { Queries as Q } from '../../../query' import mmCIF_Format = Format.mmCIF import { StructureProperties } from '../../../structure'; @@ -58,10 +58,10 @@ function operatorGroupsProvider(generators: Generator[], matrices: Matrices): () const operatorList = parseOperatorList(gen.expression); const operatorNames = expandOperators(operatorList); const operators = getAssemblyOperators(matrices, operatorNames, operatorOffset); - const selector = Query(Q.generators.atoms({ chainTest: Q.pred.and( - Q.pred.eq(StructureProperties.unit.operator_name, SymmetryOperator.DefaultName), - Q.pred.inSet(StructureProperties.chain.label_asym_id, gen.asymIds) - )})); + const selector = Q.generators.atoms({ chainTest: Q.pred.and( + Q.pred.eq(ctx => StructureProperties.unit.operator_name(ctx.element), SymmetryOperator.DefaultName), + Q.pred.inSet(ctx => StructureProperties.chain.label_asym_id(ctx.element), gen.asymIds) + )}); groups[groups.length] = { selector, operators }; operatorOffset += operators.length; } diff --git a/src/mol-model/structure/model/properties/symmetry.ts b/src/mol-model/structure/model/properties/symmetry.ts index fab3c37987b0b2c7cb36e7810ff97b93d2a9b913..c1ffee05e76c293118f5455a847157f9b820af39 100644 --- a/src/mol-model/structure/model/properties/symmetry.ts +++ b/src/mol-model/structure/model/properties/symmetry.ts @@ -6,13 +6,13 @@ import { SymmetryOperator } from 'mol-math/geometry/symmetry-operator' import { arrayFind } from 'mol-data/util' -import { Query } from '../../query' +import { StructureQuery } from '../../query' import { Model } from '../../model' import { Spacegroup } from 'mol-math/geometry'; /** Determine an atom set and a list of operators that should be applied to that set */ export interface OperatorGroup { - readonly selector: Query, + readonly selector: StructureQuery, readonly operators: ReadonlyArray<SymmetryOperator> } diff --git a/src/mol-model/structure/query.ts b/src/mol-model/structure/query.ts index 428d976d85872f423b3c4756cc77340d96844c7e..e4f3190a4303e31567ba5b95d81369ef5ad1c93e 100644 --- a/src/mol-model/structure/query.ts +++ b/src/mol-model/structure/query.ts @@ -4,8 +4,9 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import Selection from './query/selection' -import Query from './query/query' +import { StructureSelection } from './query/selection' +import { StructureQuery } from './query/query' +export * from './query/context' import * as generators from './query/generators' import * as modifiers from './query/modifiers' import pred from './query/predicates' @@ -16,4 +17,4 @@ export const Queries = { pred } -export { Selection, Query } \ No newline at end of file +export { StructureSelection, StructureQuery } \ No newline at end of file diff --git a/src/mol-model/structure/query/context.ts b/src/mol-model/structure/query/context.ts index f116f6f15e1c95941f0f2fd5ca8600fcc95040b6..eedd8d3e3988679615591e243846dee69b51a287 100644 --- a/src/mol-model/structure/query/context.ts +++ b/src/mol-model/structure/query/context.ts @@ -8,7 +8,6 @@ import { RuntimeContext } from 'mol-task'; import { Structure, StructureElement } from '../structure'; export interface QueryContextView { - readonly taskCtx: RuntimeContext; readonly element: StructureElement; } diff --git a/src/mol-model/structure/query/query.ts b/src/mol-model/structure/query/query.ts index 1985a40680e5c7b7a73a7f9cb9c689221470f669..a4c87dc503374201ae19c3f9fa125f714963a0fc 100644 --- a/src/mol-model/structure/query/query.ts +++ b/src/mol-model/structure/query/query.ts @@ -4,7 +4,7 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { RuntimeContext } from 'mol-task' +import { RuntimeContext, Task } from 'mol-task' import { Structure } from '../structure' import { StructureSelection } from './selection' import { QueryContext } from './context'; @@ -14,6 +14,10 @@ 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 { StructureQuery } \ No newline at end of file diff --git a/src/mol-model/structure/structure/symmetry.ts b/src/mol-model/structure/structure/symmetry.ts index 5c71b11142568faa9c0fbbc5a49312cd60265170..c5f8d25165114be3bdfded5d64774c03c51b3dd3 100644 --- a/src/mol-model/structure/structure/symmetry.ts +++ b/src/mol-model/structure/structure/symmetry.ts @@ -5,7 +5,7 @@ */ import Structure from './structure' -import { Selection } from '../query' +import { StructureSelection, QueryContext } from '../query' import { ModelSymmetry } from '../model' import { Task, RuntimeContext } from 'mol-task'; import { SortedArray } from 'mol-data/int'; @@ -25,12 +25,14 @@ namespace StructureSymmetry { const assembler = Structure.Builder(); + const queryCtx = new QueryContext(structure, ctx); + for (const g of assembly.operatorGroups) { - const selection = await g.selector(structure).runAsChild(ctx); - if (Selection.structureCount(selection) === 0) { + const selection = await g.selector(queryCtx); + if (StructureSelection.structureCount(selection) === 0) { continue; } - const { units } = Selection.unionStructure(selection); + const { units } = StructureSelection.unionStructure(selection); for (const oper of g.operators) { for (const unit of units) { diff --git a/src/perf-tests/structure.ts b/src/perf-tests/structure.ts index 90566d25f7202a16ad1ef7c6bb458297f41b3d29..ba9543895b7f7d0102bde4c834890f58bb23f964 100644 --- a/src/perf-tests/structure.ts +++ b/src/perf-tests/structure.ts @@ -11,7 +11,7 @@ import * as fs from 'fs' import fetch from 'node-fetch' import CIF from 'mol-io/reader/cif' -import { Structure, Model, Queries as Q, StructureElement, Selection, StructureSymmetry, Query, Format, StructureProperties as SP } from 'mol-model/structure' +import { Structure, Model, Queries as Q, StructureElement, StructureSelection, StructureSymmetry, StructureQuery, Format, StructureProperties as SP } from 'mol-model/structure' //import { Segmentation, OrderedSet } from 'mol-data/int' import to_mmCIF from 'mol-model/structure/export/mmcif' @@ -325,13 +325,13 @@ export namespace PropertyAccess { const auth_comp_id = SP.residue.auth_comp_id, op = SP.unit.operator_name; //const q1 = Q.generators.atoms({ residueTest: l => auth_comp_id(l) === 'REA' }); const q1 = Q.modifiers.includeSurroundings(Q.generators.atoms({ - chainTest: l => op(l) === '1_555', - residueTest: l => auth_comp_id(l) === 'REA' + chainTest: l => op(l.element) === '1_555', + residueTest: l => auth_comp_id(l.element) === 'REA' }), { radius: 5, wholeResidues: true }); - const surr = Selection.unionStructure(await query(Query(q1), a)); + const surr = StructureSelection.unionStructure(await StructureQuery.run(q1, a)); console.timeEnd('symmetry') // for (const u of surr.units) { @@ -371,8 +371,8 @@ export namespace PropertyAccess { // console.log('group count', uniqueGroups.groups.length); // } - function query(q: Query, s: Structure) { - return q(s).run(); + function query(q: StructureQuery, s: Structure) { + return StructureQuery.run(q, s); } export async function run() { @@ -431,14 +431,14 @@ export namespace PropertyAccess { //const auth_asym_id = SP.chain.auth_asym_id; //const set = new Set(['A', 'B', 'C', 'D']); //const q = Q.generators.atomGroups({ atomTest: l => auth_seq_id(l) < 3 }); - const q = Query(Q.generators.atoms({ atomTest: Q.pred.eq(SP.residue.auth_comp_id, 'ALA') })); + const q = Q.generators.atoms({ atomTest: Q.pred.eq(l => SP.residue.auth_comp_id(l.element), 'ALA') }); const P = SP //const q0 = Q.generators.atoms({ atomTest: l => auth_comp_id(l) === 'ALA' }); - const q1 = Query(Q.generators.atoms({ residueTest: l => auth_comp_id(l) === 'ALA' })); - const q2 = Query(Q.generators.atoms({ residueTest: l => auth_comp_id(l) === 'ALA', groupBy: SP.residue.key })); - const q3 = Query(Q.generators.atoms({ - chainTest: Q.pred.inSet(P.chain.auth_asym_id, ['A', 'B', 'C', 'D']), - residueTest: Q.pred.eq(P.residue.auth_comp_id, 'ALA') + const q1 = (Q.generators.atoms({ residueTest: l => auth_comp_id(l.element) === 'ALA' })); + const q2 = (Q.generators.atoms({ residueTest: l => auth_comp_id(l.element) === 'ALA', groupBy: l => SP.residue.key(l.element) })); + const q3 = (Q.generators.atoms({ + chainTest: Q.pred.inSet(l => P.chain.auth_asym_id(l.element), ['A', 'B', 'C', 'D']), + residueTest: Q.pred.eq(l => P.residue.auth_comp_id(l.element), 'ALA') })); await query(q, structures[0]); //console.log(to_mmCIF('test', Selection.union(q0r))); @@ -452,7 +452,7 @@ export namespace PropertyAccess { console.time('q2') const q2r = await query(q2, structures[0]); console.timeEnd('q2') - console.log(Selection.structureCount(q2r)); + console.log(StructureSelection.structureCount(q2r)); //console.log(q1(structures[0])); const col = models[0].atomicConformation.atomId.value; diff --git a/src/servers/model/server/api.ts b/src/servers/model/server/api.ts index 0e60d47074d27b278086f6eb3015906ae65153b9..95879cce0d577d835c825e8c12f643b6cc4878e5 100644 --- a/src/servers/model/server/api.ts +++ b/src/servers/model/server/api.ts @@ -4,7 +4,7 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { Query, Queries, Structure, StructureElement, StructureSymmetry, StructureProperties as Props } from 'mol-model/structure'; +import { StructureQuery, Queries, Structure, StructureElement, StructureSymmetry, StructureProperties as Props, QueryPredicate } from 'mol-model/structure'; export enum QueryParamType { String, @@ -26,7 +26,7 @@ export interface QueryDefinition { name: string, niceName: string, exampleId: string, // default is 1cbs - query: (params: any, structure: Structure) => Query, + query: (params: any, structure: Structure) => StructureQuery, description: string, params: QueryParamInfo[], structureTransform?: (params: any, s: Structure) => Promise<Structure> @@ -51,25 +51,25 @@ const AtomSiteParameters = { // return Element.property(l => p(l) === id); // } -function entityTest1_555(params: any): StructureElement.Predicate | undefined { - if (typeof params.entity_id === 'undefined') return StructureElement.property(l => l.unit.conformation.operator.isIdentity); +function entityTest1_555(params: any): QueryPredicate | undefined { + if (typeof params.entity_id === 'undefined') return ctx => ctx.element.unit.conformation.operator.isIdentity; const p = Props.entity.id, id = '' + params.entityId; - return StructureElement.property(l => l.unit.conformation.operator.isIdentity && p(l) === id); + return ctx => ctx.element.unit.conformation.operator.isIdentity && p(ctx.element) === id; } -function chainTest(params: any): StructureElement.Predicate | undefined { +function chainTest(params: any): QueryPredicate | undefined { if (typeof params.label_asym_id !== 'undefined') { const p = Props.chain.label_asym_id, id = '' + params.label_asym_id; - return StructureElement.property(l => p(l) === id); + return ctx => p(ctx.element) === id; } if (typeof params.auth_asym_id !== 'undefined') { const p = Props.chain.auth_asym_id, id = '' + params.auth_asym_id; - return StructureElement.property(l => p(l) === id); + return ctx => p(ctx.element) === id; } return void 0; } -function residueTest(params: any): StructureElement.Predicate | undefined { +function residueTest(params: any): QueryPredicate | undefined { const props: StructureElement.Property<any>[] = [], values: any[] = []; if (typeof params.label_seq_id !== 'undefined') { @@ -99,15 +99,15 @@ function residueTest(params: any): StructureElement.Predicate | undefined { switch (props.length) { case 0: return void 0; - case 1: return StructureElement.property(l => props[0](l) === values[0]); - case 2: return StructureElement.property(l => props[0](l) === values[0] && props[1](l) === values[1]); - case 3: return StructureElement.property(l => props[0](l) === values[0] && props[1](l) === values[1] && props[2](l) === values[2]); + case 1: return ctx => props[0](ctx.element) === values[0]; + case 2: return ctx => props[0](ctx.element) === values[0] && props[1](ctx.element) === values[1]; + case 3: return ctx => props[0](ctx.element) === values[0] && props[1](ctx.element) === values[1] && props[2](ctx.element) === values[2]; default: { const len = props.length; - return StructureElement.property(l => { - for (let i = 0; i < len; i++) if (!props[i](l) !== values[i]) return false; + return ctx => { + for (let i = 0; i < len; i++) if (!props[i](ctx.element) !== values[i]) return false; return true; - }); + }; } } } @@ -117,13 +117,13 @@ function residueTest(params: any): StructureElement.Predicate | undefined { // } const QueryMap: { [id: string]: Partial<QueryDefinition> } = { - 'full': { niceName: 'Full Structure', query: () => Query(Queries.generators.all), description: 'The full structure.' }, + 'full': { niceName: 'Full Structure', query: () => Queries.generators.all, description: 'The full structure.' }, 'residueInteraction': { niceName: 'Residues Inside a Sphere', description: 'Identifies all residues within the given radius from the source residue.', query(p) { const center = Queries.generators.atoms({ entityTest: entityTest1_555(p), chainTest: chainTest(p), residueTest: residueTest(p) }); - return Query(Queries.modifiers.includeSurroundings(center, { radius: p.radius, wholeResidues: true })); + return Queries.modifiers.includeSurroundings(center, { radius: p.radius, wholeResidues: true }); }, structureTransform(p, s) { return StructureSymmetry.builderSymmetryMates(s, p.radius).run(); diff --git a/src/servers/model/server/query.ts b/src/servers/model/server/query.ts index 2dc635c4ee79bdeaa7735533615cd7a49a7e2f5d..4a1049524fb9698e8a8d63d71e21e5700718f6c6 100644 --- a/src/servers/model/server/query.ts +++ b/src/servers/model/server/query.ts @@ -13,7 +13,7 @@ import { ConsoleLogger } from 'mol-util/console-logger'; import Writer from 'mol-io/writer/writer'; import { CifWriter } from 'mol-io/writer/cif' import { encode_mmCIF_categories } from 'mol-model/structure/export/mmcif'; -import { Selection } from 'mol-model/structure'; +import { StructureSelection, StructureQuery } from 'mol-model/structure'; import Version from '../version' import { Column } from 'mol-data/db'; import { PerformanceMonitor } from 'mol-util/performance-monitor'; @@ -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 = Selection.unionStructure(await query(structure).run(abortingObserver, 250)); + const result = StructureSelection.unionStructure(await StructureQuery.asTask(query, structure).run(abortingObserver, 250)); perf.end('query'); ConsoleLogger.logId(req.id, 'Query', 'Query finished.');