ソースを参照

Merged mol-model branch

David Sehnal 7 年 前
コミット
229043d93e

+ 40 - 0
src/mol-model/annotation/annotation.ts

@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { Structure, ElementSet, Element } from '../structure'
+
+interface Annotation<E = any> {
+    definition: Annotation.Definition<E>,
+    getValue(l: Element.Location): E | undefined,
+    getAll(l: ElementSet): { annotations: E[], /* TODO: map annotations to elements */ }
+}
+
+namespace Annotation {
+    export const enum Kind {
+        Atom,
+        Residue,
+        Sequence,
+        Chain,
+        Entity,
+        Coarse,
+        Spatial
+    }
+
+    export const enum Type {
+        Num,
+        Str,
+        Obj
+    }
+
+    export interface Definition<E = any> {
+        name: string,
+        kind: Kind,
+        type: Type,
+        prepare<Data>(s: Structure, data: Data): Annotation<E>,
+    }
+}
+
+export { Annotation }

+ 17 - 0
src/mol-model/annotations.ts

@@ -0,0 +1,17 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { Annotation } from './annotation/annotation'
+import { UUID } from 'mol-util'
+
+interface Annotations {
+    id: UUID,
+    all: Annotation[],
+    byKind: { [kind: number]: Annotation }
+    //getAll()
+}
+
+export { Annotations }

+ 3 - 3
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 } from '../../../query'
+import { Queries as Q, Query } from '../../../query'
 
 import mmCIF_Format = Format.mmCIF
 
@@ -57,10 +57,10 @@ function operatorGroupsProvider(generators: Generator[], matrices: Matrices): ()
             const operatorList = parseOperatorList(gen.expression);
             const operatorNames = expandOperators(operatorList);
             const operators = getAssemblyOperators(matrices, operatorNames, operatorOffset);
-            const selector = Q.generators.atoms({ chainTest: Q.pred.and(
+            const selector = Query(Q.generators.atoms({ chainTest: Q.pred.and(
                 Q.pred.eq(Q.props.unit.operator_name, SymmetryOperator.DefaultName),
                 Q.pred.inSet(Q.props.chain.label_asym_id, gen.asymIds)
-            )});
+            )}));
             groups[groups.length] = { selector, operators };
             operatorOffset += operators.length;
         }

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

@@ -14,6 +14,7 @@ import CoarseGrained from './properties/coarse-grained'
 import from_gro from './formats/gro'
 import from_mmCIF from './formats/mmcif'
 
+import { Annotations } from '../../annotations'
 
 /**
  * Interface to the "source data" of the molecule.
@@ -31,6 +32,7 @@ interface Model extends Readonly<{
     conformation: Conformation,
     symmetry: Symmetry,
     coarseGrained: CoarseGrained,
+    annotations: Annotations,
 
     atomCount: number,
 }> {

+ 14 - 8
src/mol-model/structure/query/generators.ts

@@ -10,7 +10,7 @@ import P from './properties'
 import { Structure, ElementSet, Element } from '../structure'
 import { OrderedSet, Segmentation } from 'mol-data/int'
 
-export const all: Query = s => Selection.Singletons(s, s.elements);
+export const all: Query.Provider = async (s, ctx) => Selection.Singletons(s, s.elements);
 
 export interface AtomQueryParams {
     entityTest: Element.Predicate,
@@ -27,7 +27,7 @@ export interface AtomGroupsQueryParams extends AtomQueryParams {
 export function residues(params?: Partial<AtomQueryParams>) { return atoms({ ...params, groupBy: P.residue.key }); }
 export function chains(params?: Partial<AtomQueryParams>) { return atoms({ ...params, groupBy: P.chain.key }); }
 
-export function atoms(params?: Partial<AtomGroupsQueryParams>): Query {
+export function atoms(params?: Partial<AtomGroupsQueryParams>): Query.Provider {
     if (!params || (!params.atomTest && !params.residueTest && !params.chainTest && !params.entityTest && !params.groupBy)) return all;
     if (!!params.atomTest && !params.residueTest && !params.chainTest && !params.entityTest && !params.groupBy) return atomGroupsLinear(params.atomTest);
 
@@ -43,8 +43,8 @@ export function atoms(params?: Partial<AtomGroupsQueryParams>): Query {
     return atomGroupsGrouped(normalized);
 }
 
-function atomGroupsLinear(atomTest: Element.Predicate): Query {
-    return structure => {
+function atomGroupsLinear(atomTest: Element.Predicate): Query.Provider {
+    return async (structure, ctx) => {
         const { elements, units } = structure;
         const unitIds = ElementSet.unitIds(elements);
         const l = Element.Location();
@@ -61,14 +61,16 @@ function atomGroupsLinear(atomTest: Element.Predicate): Query {
                 if (atomTest(l)) builder.addToUnit(l.element);
             }
             builder.commitUnit(unitId);
+
+            if (ctx.shouldUpdate) await ctx.update({ message: 'Atom Groups', current: 0, max: unitIds.length });
         }
 
         return Selection.Singletons(structure, builder.getSet());
     };
 }
 
-function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: AtomGroupsQueryParams): Query {
-    return structure => {
+function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: AtomGroupsQueryParams): Query.Provider {
+    return async (structure, ctx) => {
         const { elements, units } = structure;
         const unitIds = ElementSet.unitIds(elements);
         const l = Element.Location();
@@ -104,6 +106,8 @@ function atomGroupsSegmented({ entityTest, chainTest, residueTest, atomTest }: A
                 }
             }
             builder.commitUnit(unitId);
+
+            if (ctx.shouldUpdate) await ctx.update({ message: 'Atom Groups', current: 0, max: unitIds.length });
         }
 
         return Selection.Singletons(structure, builder.getSet());
@@ -157,8 +161,8 @@ class LinearGroupingBuilder {
     constructor(private structure: Structure) { }
 }
 
-function atomGroupsGrouped({ entityTest, chainTest, residueTest, atomTest, groupBy }: AtomGroupsQueryParams): Query {
-    return structure => {
+function atomGroupsGrouped({ entityTest, chainTest, residueTest, atomTest, groupBy }: AtomGroupsQueryParams): Query.Provider {
+    return async (structure, ctx) => {
         const { elements, units } = structure;
         const unitIds = ElementSet.unitIds(elements);
         const l = Element.Location();
@@ -192,6 +196,8 @@ function atomGroupsGrouped({ entityTest, chainTest, residueTest, atomTest, group
                     }
                 }
             }
+
+            if (ctx.shouldUpdate) await ctx.update({ message: 'Atom Groups', current: 0, max: unitIds.length });
         }
 
         return builder.getSelection();

+ 12 - 1
src/mol-model/structure/query/query.ts

@@ -4,10 +4,21 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
+import { Task, RuntimeContext } from 'mol-task'
 import { Structure } from '../structure'
 import Selection from './selection'
 
 // TODO: Query { (s: Structure): Computation<Selection> }
 
-interface Query { (s: Structure): Selection }
+interface Query { (s: Structure): Task<Selection>, provider: Query.Provider }
+function Query(q: Query.Provider): Query {
+    const ret = (s => Task.create('Query', ctx => q(s, ctx))) as Query;
+    ret.provider = q;
+    return ret;
+}
+
+namespace Query {
+    export interface Provider { (s: Structure, ctx: RuntimeContext): Promise<Selection> }
+}
+
 export default Query

+ 20 - 17
src/mol-model/structure/structure/symmetry.ts

@@ -9,36 +9,39 @@ import ElementSet from './element/set'
 import Unit from './unit'
 import { Selection } from '../query'
 import { ModelSymmetry } from '../model'
+import { Task } from 'mol-task';
 
 namespace Symmetry {
-    export const  buildAssembly = buildAssemblyImpl;
+    export const buildAssembly = buildAssemblyImpl;
 }
 
 export default Symmetry;
 
 function buildAssemblyImpl(structure: Structure, name: string) {
-    const models = Structure.getModels(structure);
-    if (models.length !== 1) throw new Error('Can only build assemblies from structures based on 1 model.');
+    return Task.create('Build Symmetry', async ctx => {
+        const models = Structure.getModels(structure);
+        if (models.length !== 1) throw new Error('Can only build assemblies from structures based on 1 model.');
 
-    const assembly = ModelSymmetry.findAssembly(models[0], name);
-    if (!assembly) throw new Error(`Assembly '${name}' is not defined.`);
+        const assembly = ModelSymmetry.findAssembly(models[0], name);
+        if (!assembly) throw new Error(`Assembly '${name}' is not defined.`);
 
-    const assembler = Structure.Builder();
+        const assembler = Structure.Builder();
 
-    for (const g of assembly.operatorGroups) {
-        const selection = g.selector(structure);
-        if (Selection.structureCount(selection) === 0) continue;
-        const { units, elements } = Selection.unionStructure(selection);
+        for (const g of assembly.operatorGroups) {
+            const selection = await ctx.runChild(g.selector(structure));
+            if (Selection.structureCount(selection) === 0) continue;
+            const { units, elements } = Selection.unionStructure(selection);
 
-        const unitIds = ElementSet.unitIds(elements);
+            const unitIds = ElementSet.unitIds(elements);
 
-        for (const oper of g.operators) {
-            for (let uI = 0, _uI = unitIds.length; uI < _uI; uI++) {
-                const unit = units[unitIds[uI]];
-                assembler.add(Unit.withOperator(unit, oper), ElementSet.unitGetByIndex(elements, uI));
+            for (const oper of g.operators) {
+                for (let uI = 0, _uI = unitIds.length; uI < _uI; uI++) {
+                    const unit = units[unitIds[uI]];
+                    assembler.add(Unit.withOperator(unit, oper), ElementSet.unitGetByIndex(elements, uI));
+                }
             }
         }
-    }
 
-    return assembler.getStructure();
+        return assembler.getStructure();
+    });
 }

+ 20 - 16
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, Element, ElementGroup, ElementSet, Selection, Symmetry, Unit } from 'mol-model/structure'
+import { Structure, Model, Queries as Q, Element, ElementGroup, ElementSet, Selection, Symmetry, Unit, Query } from 'mol-model/structure'
 import { Segmentation, OrderedSet } from 'mol-data/int'
 
 import to_mmCIF from 'mol-model/structure/export/mmcif'
@@ -294,16 +294,16 @@ export namespace PropertyAccess {
         console.log(to_mmCIF('test', s));
     }
 
-    export function testAssembly(id: string, s: Structure) {
+    export async function testAssembly(id: string, s: Structure) {
         console.time('assembly')
-        const a = Symmetry.buildAssembly(s, '1');
+        const a = await Run(Symmetry.buildAssembly(s, '1'));
         console.timeEnd('assembly')
         fs.writeFileSync(`${DATA_DIR}/${id}_assembly.bcif`, to_mmCIF(id, a, true));
         console.log('exported');
     }
 
-    export function testGrouping(structure: Structure) {
-        const { elements, units } = Symmetry.buildAssembly(structure, '1');
+    export async function testGrouping(structure: Structure) {
+        const { elements, units } = await Run(Symmetry.buildAssembly(structure, '1'));
         console.log('grouping', units.length);
         console.log('built asm');
 
@@ -321,6 +321,10 @@ export namespace PropertyAccess {
         console.log('group count', uniqueGroups.groups.length);
     }
 
+    function query(q: Query, s: Structure) {
+        return Run((q(s)));
+    }
+
     export async function run() {
         //const { structures, models/*, mmcif*/ } = await getBcif('1cbs');
         // const { structures, models } = await getBcif('3j3q');
@@ -375,26 +379,26 @@ export namespace PropertyAccess {
         //const auth_asym_id = Q.props.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 = Q.generators.atoms({ atomTest: Q.pred.eq(Q.props.residue.auth_comp_id, 'ALA') });
+        const q = Query(Q.generators.atoms({ atomTest: Q.pred.eq(Q.props.residue.auth_comp_id, 'ALA') }));
         const P = Q.props
         //const q0 = Q.generators.atoms({ atomTest: l => auth_comp_id(l) === 'ALA' });
-        const q1 = Q.generators.atoms({ residueTest: l => auth_comp_id(l) === 'ALA' });
-        const q2 = Q.generators.atoms({ residueTest: l => auth_comp_id(l) === 'ALA', groupBy: Q.props.residue.key });
-        const q3 = Q.generators.atoms({
+        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: Q.props.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')
-        });
-        q(structures[0]);
+        }));
+        await query(q, structures[0]);
         //console.log(to_mmCIF('test', Selection.union(q0r)));
 
         console.time('q1')
-        q1(structures[0]);
+        await query(q1, structures[0]);
         console.timeEnd('q1')
         console.time('q1')
-        q1(structures[0]);
+        await query(q1, structures[0]);
         console.timeEnd('q1')
         console.time('q2')
-        const q2r = q2(structures[0]);
+        const q2r = await query(q2, structures[0]);
         console.timeEnd('q2')
         console.log(Selection.structureCount(q2r));
         //console.log(q1(structures[0]));
@@ -404,8 +408,8 @@ export namespace PropertyAccess {
         suite
             //.add('test q', () => q1(structures[0]))
             //.add('test q', () => q(structures[0]))
-            .add('test q1', () => q1(structures[0]))
-            .add('test q3', () => q3(structures[0]))
+            .add('test q1', async () => await q1(structures[0]))
+            .add('test q3', async () => await q3(structures[0]))
             //.add('test int', () => sumProperty(structures[0], l => col(l.element))
             // .add('sum residue', () => sumPropertyResidue(structures[0], l => l.unit.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.atom])))