Przeglądaj źródła

Coarse grained units

David Sehnal 7 lat temu
rodzic
commit
7d4b9d1537

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

@@ -12,6 +12,7 @@ import Format from '../format'
 import Model from '../model'
 import * as Hierarchy from '../properties/hierarchy'
 import Conformation from '../properties/conformation'
+import CoarseGrained from '../properties/coarse-grained'
 import findHierarchyKeys from '../utils/hierarchy-keys'
 import { guessElement } from '../utils/guess-element'
 import { ElementSymbol} from '../types'
@@ -117,6 +118,7 @@ function createModel(format: gro_Format, modelNum: number, previous?: Model): Mo
         modelNum,
         hierarchy: { ...hierarchyData, ...hierarchyKeys, ...hierarchySegments },
         conformation: getConformation(structure.atoms),
+        coarseGrained: CoarseGrained.Empty,
         symmetry: { assemblies: [] },
         atomCount: structure.atoms.count
     };

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

@@ -11,6 +11,7 @@ import Format from '../format'
 import Model from '../model'
 import * as Hierarchy from '../properties/hierarchy'
 import Conformation from '../properties/conformation'
+import CoarseGrained from '../properties/coarse-grained'
 import Symmetry from '../properties/symmetry'
 import findHierarchyKeys from '../utils/hierarchy-keys'
 import { ElementSymbol} from '../types'
@@ -111,6 +112,7 @@ function createModel(format: mmCIF_Format, bounds: Interval, previous?: Model):
         modelNum: format.data.atom_site.pdbx_PDB_model_num.value(Interval.start(bounds)),
         hierarchy: { ...hierarchyData, ...hierarchyKeys, ...hierarchySegments },
         conformation: getConformation(format, bounds),
+        coarseGrained: CoarseGrained.Empty,
         symmetry: getSymmetry(format),
         atomCount: Interval.size(bounds)
     };

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

@@ -11,6 +11,7 @@ import Hierarchy from './properties/hierarchy'
 import Conformation from './properties/conformation'
 import Symmetry from './properties/symmetry'
 import Bonds from './properties/bonds'
+import CoarseGrained from './properties/coarse-grained'
 
 import computeBonds from './utils/compute-bonds'
 
@@ -33,6 +34,7 @@ interface Model extends Readonly<{
     hierarchy: Hierarchy,
     conformation: Conformation,
     symmetry: Symmetry,
+    coarseGrained: CoarseGrained,
 
     atomCount: number,
 }> {

+ 15 - 0
src/mol-model/structure/model/properties/coarse-grained.ts

@@ -0,0 +1,15 @@
+/**
+ * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+interface CoarseGrained {
+    // TODO
+}
+
+namespace CoarseGrained {
+    export const Empty: CoarseGrained = { };
+}
+
+export default CoarseGrained;

+ 21 - 17
src/mol-model/structure/query/properties.ts

@@ -4,7 +4,7 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { Atom } from '../structure'
+import { Atom, Unit } from '../structure'
 
 const constant = {
     true: Atom.property(l => true),
@@ -12,6 +12,10 @@ const constant = {
     zero: Atom.property(l => 0)
 }
 
+function notAtomic(): never {
+    throw 'Property only available for atomic models.';
+}
+
 const atom = {
     key: Atom.property(l => l.atom),
 
@@ -19,9 +23,9 @@ const atom = {
     x: Atom.property(l => l.unit.x(l.atom)),
     y: Atom.property(l => l.unit.y(l.atom)),
     z: Atom.property(l => l.unit.z(l.atom)),
-    id: Atom.property(l => l.unit.conformation.atomId.value(l.atom)),
-    occupancy: Atom.property(l => l.unit.conformation.occupancy.value(l.atom)),
-    B_iso_or_equiv: Atom.property(l => l.unit.conformation.B_iso_or_equiv.value(l.atom)),
+    id: Atom.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.conformation.atomId.value(l.atom)),
+    occupancy: Atom.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.conformation.occupancy.value(l.atom)),
+    B_iso_or_equiv: Atom.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.conformation.B_iso_or_equiv.value(l.atom)),
 
     // Hierarchy
     type_symbol: Atom.property(l => l.unit.hierarchy.atoms.type_symbol.value(l.atom)),
@@ -32,25 +36,25 @@ const atom = {
 }
 
 const residue = {
-    key: Atom.property(l => l.unit.hierarchy.residueKey.value(l.unit.residueIndex[l.atom])),
-
-    group_PDB: Atom.property(l => l.unit.hierarchy.residues.group_PDB.value(l.unit.residueIndex[l.atom])),
-    label_comp_id: Atom.property(l => l.unit.hierarchy.residues.label_comp_id.value(l.unit.residueIndex[l.atom])),
-    auth_comp_id: Atom.property(l => l.unit.hierarchy.residues.auth_comp_id.value(l.unit.residueIndex[l.atom])),
-    label_seq_id: Atom.property(l => l.unit.hierarchy.residues.label_seq_id.value(l.unit.residueIndex[l.atom])),
-    auth_seq_id: Atom.property(l => l.unit.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.atom])),
-    pdbx_PDB_ins_code: Atom.property(l => l.unit.hierarchy.residues.pdbx_PDB_ins_code.value(l.unit.residueIndex[l.atom]))
+    key: Atom.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.residueKey.value(l.unit.residueIndex[l.atom])),
+
+    group_PDB: Atom.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.residues.group_PDB.value(l.unit.residueIndex[l.atom])),
+    label_comp_id: Atom.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.residues.label_comp_id.value(l.unit.residueIndex[l.atom])),
+    auth_comp_id: Atom.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.residues.auth_comp_id.value(l.unit.residueIndex[l.atom])),
+    label_seq_id: Atom.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.residues.label_seq_id.value(l.unit.residueIndex[l.atom])),
+    auth_seq_id: Atom.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.atom])),
+    pdbx_PDB_ins_code: Atom.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.residues.pdbx_PDB_ins_code.value(l.unit.residueIndex[l.atom]))
 }
 
 const chain = {
-    key: Atom.property(l => l.unit.hierarchy.chainKey.value(l.unit.chainIndex[l.atom])),
+    key: Atom.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.chainKey.value(l.unit.chainIndex[l.atom])),
 
-    label_asym_id: Atom.property(l => l.unit.hierarchy.chains.label_asym_id.value(l.unit.chainIndex[l.atom])),
-    auth_asym_id: Atom.property(l => l.unit.hierarchy.chains.auth_asym_id.value(l.unit.chainIndex[l.atom])),
-    label_entity_id: Atom.property(l => l.unit.hierarchy.chains.label_entity_id.value(l.unit.chainIndex[l.atom]))
+    label_asym_id: Atom.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.chains.label_asym_id.value(l.unit.chainIndex[l.atom])),
+    auth_asym_id: Atom.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.chains.auth_asym_id.value(l.unit.chainIndex[l.atom])),
+    label_entity_id: Atom.property(l => !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.chains.label_entity_id.value(l.unit.chainIndex[l.atom]))
 }
 
-function eK(l: Atom.Location) { return l.unit.hierarchy.entityKey.value(l.unit.chainIndex[l.atom]); }
+function eK(l: Atom.Location) { return !Unit.isAtomic(l.unit) ? notAtomic() : l.unit.hierarchy.entityKey.value(l.unit.chainIndex[l.atom]); }
 
 const entity = {
     key: eK,

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

@@ -35,7 +35,7 @@ namespace Structure {
 
         for (let c = 0; c < chains.count; c++) {
             const group = AtomGroup.createNew(OrderedSet.ofBounds(chains.segments[c], chains.segments[c + 1]));
-            const unit = Unit.create(model, SymmetryOperator.Default, group);
+            const unit = Unit.createAtomic(model, SymmetryOperator.Default, group);
             builder.add(unit, unit.fullGroup);
         }
 

+ 55 - 30
src/mol-model/structure/structure/unit.ts

@@ -8,41 +8,59 @@ import SymmetryOperator from 'mol-math/geometry/symmetry-operator'
 import AtomGroup from './atom/group'
 import { Model } from '../model'
 
-// A bulding block of a structure that corresponds
-// to a "natural group of atoms" (most often a "chain")
-// together with a tranformation (rotation and translation)
-// that is dynamically applied to the underlying atom set.
-//
-// An atom set can be referenced by multiple diffrent units which
-// makes construction of assemblies and spacegroups very efficient.
-interface Unit extends SymmetryOperator.ArrayMapping {
-    // Provides access to the underlying data.
-    readonly model: Model,
-
-    // The "full" atom group corresponding to this unit.
-    // Every selection is a subset of this atoms group.
-    // Things like inter-unit bonds or spatial lookups
-    // can be be implemented efficiently as "views" of the
-    // full group.
-    readonly fullGroup: AtomGroup,
-
-    // Reference some commonly accessed things for faster access.
-    readonly residueIndex: ArrayLike<number>,
-    readonly chainIndex: ArrayLike<number>,
-    readonly hierarchy: Model['hierarchy'],
-    readonly conformation: Model['conformation']
-
-    // TODO: add velocity?
-    // AR: would fit into conformation, right?
-}
+// A building block of a structure that corresponds to an atomic or a coarse grained representation
+// 'conveniently grouped together'.
+type Unit = Unit.Atomic | Unit.Coarse
 
 namespace Unit {
-    export function create(model: Model, operator: SymmetryOperator, fullGroup: AtomGroup): Unit {
+    export const enum Kind { Atomic, Coarse }
+
+    export function isAtomic(u: Unit): u is Atomic { return u.kind === Kind.Atomic; }
+    export function isCoarse(u: Unit): u is Coarse { return u.kind === Kind.Coarse; }
+
+    export interface Base extends SymmetryOperator.ArrayMapping {
+        // Provides access to the underlying data.
+        readonly model: Model,
+
+        // The "full" atom group corresponding to this unit.
+        // Every selection is a subset of this atoms group.
+        // Things like inter-unit bonds or spatial lookups
+        // can be be implemented efficiently as "views" of the
+        // full group.
+        readonly fullGroup: AtomGroup,
+
+        readonly hierarchy: Model['hierarchy'],
+    }
+
+    // A bulding block of a structure that corresponds
+    // to a "natural group of atoms" (most often a "chain")
+    // together with a tranformation (rotation and translation)
+    // that is dynamically applied to the underlying atom set.
+    //
+    // An atom set can be referenced by multiple diffrent units which
+    // makes construction of assemblies and spacegroups very efficient.
+    export interface Atomic extends Base {
+        readonly kind: Unit.Kind.Atomic,
+
+        // Reference some commonly accessed things for faster access.
+        readonly residueIndex: ArrayLike<number>,
+        readonly chainIndex: ArrayLike<number>,
+        readonly conformation: Model['conformation']
+    }
+
+    // Coarse grained representations.
+    // TODO: can we use the ArrayMapping here?
+    export interface Coarse extends Base  {
+        readonly kind: Unit.Kind.Coarse
+    }
+
+    export function createAtomic(model: Model, operator: SymmetryOperator, fullGroup: AtomGroup): Unit {
         const h = model.hierarchy;
         const { invariantPosition, position, x, y, z } = SymmetryOperator.createMapping(operator, model.conformation);
 
         return {
             model,
+            kind: Kind.Atomic,
             operator,
             fullGroup,
             residueIndex: h.residueSegments.segmentMap,
@@ -55,8 +73,15 @@ namespace Unit {
         };
     }
 
-    export function withOperator(unit: Unit, operator: SymmetryOperator) {
-        return create(unit.model, SymmetryOperator.compose(unit.operator, operator), unit.fullGroup);
+    export function createCoarse(model: Model, operator: SymmetryOperator, fullGroup: AtomGroup): Unit {
+        throw 'not implemented'
+    }
+
+    export function withOperator(unit: Unit, operator: SymmetryOperator): Unit {
+        switch (unit.kind) {
+            case Kind.Atomic: return createAtomic(unit.model, SymmetryOperator.compose(unit.operator, operator), unit.fullGroup);
+            case Kind.Coarse: return createCoarse(unit.model, SymmetryOperator.compose(unit.operator, operator), unit.fullGroup);
+        }
     }
 }
 

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

@@ -177,26 +177,26 @@ export namespace PropertyAccess {
         return s;
     }
 
-    function sumPropertyResidue(structure: Structure, p: Atom.Property<number>) {
-        const { atoms, units } = structure;
-        const unitIds = AtomSet.unitIds(atoms);
-        const l = Atom.Location();
+    // function sumPropertyResidue(structure: Structure, p: Atom.Property<number>) {
+    //     const { atoms, units } = structure;
+    //     const unitIds = AtomSet.unitIds(atoms);
+    //     const l = Atom.Location();
 
-        let s = 0;
+    //     let s = 0;
 
-        for (let i = 0, _i = unitIds.length; i < _i; i++) {
-            const unit = units[unitIds[i]];
-            l.unit = unit;
-            const set = AtomSet.unitGetByIndex(atoms, i);
-            const residuesIt = Segmentation.transientSegments(unit.hierarchy.residueSegments, set.atoms);
-            while (residuesIt.hasNext) {
-                l.atom = AtomGroup.getAt(set, residuesIt.move().start);
-                s += p(l);
-            }
-        }
+    //     for (let i = 0, _i = unitIds.length; i < _i; i++) {
+    //         const unit = units[unitIds[i]];
+    //         l.unit = unit;
+    //         const set = AtomSet.unitGetByIndex(atoms, i);
+    //         const residuesIt = Segmentation.transientSegments(unit.hierarchy.residueSegments, set.atoms);
+    //         while (residuesIt.hasNext) {
+    //             l.atom = AtomGroup.getAt(set, residuesIt.move().start);
+    //             s += p(l);
+    //         }
+    //     }
 
-        return s;
-    }
+    //     return s;
+    // }
 
     function sumPropertyAtomSetIt(structure: Structure, p: Atom.Property<number>) {
         const { atoms, units } = structure;
@@ -243,26 +243,26 @@ export namespace PropertyAccess {
     //     return s;
     // }
 
-    function sumDirect(structure: Structure) {
-        const { atoms, units } = structure;
-        const unitIds = AtomSet.unitIds(atoms);
+    // function sumDirect(structure: Structure) {
+    //     const { atoms, units } = structure;
+    //     const unitIds = AtomSet.unitIds(atoms);
 
-        let s = 0;
+    //     let s = 0;
 
-        for (let i = 0, _i = unitIds.length; i < _i; i++) {
-            const unitId = unitIds[i];
-            const unit = units[unitId];
-            const set = AtomSet.unitGetByIndex(atoms, i);
-            //const { residueIndex, chainIndex } = unit;
-            const p = unit.conformation.atomId.value;
-            for (let j = 0, _j = AtomGroup.size(set); j < _j; j++) {
-                const aI = AtomGroup.getAt(set, j);
-                s += p(aI);
-            }
-        }
+    //     for (let i = 0, _i = unitIds.length; i < _i; i++) {
+    //         const unitId = unitIds[i];
+    //         const unit = units[unitId];
+    //         const set = AtomSet.unitGetByIndex(atoms, i);
+    //         //const { residueIndex, chainIndex } = unit;
+    //         const p = unit.conformation.atomId.value;
+    //         for (let j = 0, _j = AtomGroup.size(set); j < _j; j++) {
+    //             const aI = AtomGroup.getAt(set, j);
+    //             s += p(aI);
+    //         }
+    //     }
 
-        return s;
-    }
+    //     return s;
+    // }
 
     // function concatProperty(structure: Structure, p: Property<string>) {
     //     const { atoms, units } = structure;
@@ -333,14 +333,14 @@ export namespace PropertyAccess {
         //console.log(sumPropertySegmentedMutable(structures[0], l => l.unit.model.conformation.atomId.value(l.atom)));
         console.log(sumPropertyAtomSetIt(structures[0], l => l.unit.model.conformation.atomId.value(l.atom)));
         //console.log(sumProperty(structures[0], Property.cachedAtomColumn(m => m.conformation.atomId)));
-        console.log(sumDirect(structures[0]));
-        console.log('r', sumPropertyResidue(structures[0], l => l.unit.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.atom])));
+        //console.log(sumDirect(structures[0]));
+        //console.log('r', sumPropertyResidue(structures[0], l => l.unit.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.atom])));
 
         console.time('atom.x');
         console.log('atom.x', sumProperty(structures[0], Q.props.atom.x));
         console.timeEnd('atom.x');
         console.time('__x')
-        console.log('__x', sumProperty(structures[0], l => l.unit.conformation.x[l.atom]));
+        //console.log('__x', sumProperty(structures[0], l => l.unit.conformation.x[l.atom]));
         console.timeEnd('__x')
 
         //const authSeqId = Atom.property(l => l.unit.hierarchy.residues.auth_seq_id.value(l.unit.residueIndex[l.atom]));