diff --git a/src/mol-base/collections/integer/impl/ordered-set.ts b/src/mol-base/collections/integer/impl/ordered-set.ts index 4dfeb269106756bd2e1b82849fad6ad9e4669d3c..68e152c0da9815587cca06d3d25d940a17e6509e 100644 --- a/src/mol-base/collections/integer/impl/ordered-set.ts +++ b/src/mol-base/collections/integer/impl/ordered-set.ts @@ -14,6 +14,7 @@ export const Empty: OrderedSetImpl = I.Empty; export const ofSingleton = I.ofSingleton export const ofRange = I.ofRange +export const ofBounds = I.ofBounds export function ofSortedArray(xs: Nums): OrderedSetImpl { if (!xs.length) return Empty; diff --git a/src/mol-base/collections/integer/ordered-set.ts b/src/mol-base/collections/integer/ordered-set.ts index 76bb495cf2bedbf5e4b973fdd7eedc6de83f6844..ab7af67becfb4362f6890e0bff077d640d4859e1 100644 --- a/src/mol-base/collections/integer/ordered-set.ts +++ b/src/mol-base/collections/integer/ordered-set.ts @@ -11,6 +11,7 @@ namespace OrderedSet { export const Empty: OrderedSet = Base.Empty as any; export const ofSingleton: (value: number) => OrderedSet = Base.ofSingleton as any; export const ofRange: (min: number, max: number) => OrderedSet = Base.ofRange as any; + export const ofBounds: (min: number, max: number) => OrderedSet = Base.ofBounds as any; /** It is the responsibility of the caller to ensure the array is sorted and contains unique values. */ export const ofSortedArray: (xs: ArrayLike<number>) => OrderedSet = Base.ofSortedArray as any; diff --git a/src/mol-base/collections/integer/segmentation.ts b/src/mol-base/collections/integer/segmentation.ts index dda6b63a3a0ca1b5b30125e6c6ba562fa5effb0a..3be8cc7c345bc8be093020576abdbc21f55877f0 100644 --- a/src/mol-base/collections/integer/segmentation.ts +++ b/src/mol-base/collections/integer/segmentation.ts @@ -24,6 +24,7 @@ namespace Segmentation { interface Segmentation { '@type': 'segmentation', + readonly segments: ArrayLike<number>, readonly segmentMap: ArrayLike<number>, readonly count: number } diff --git a/src/mol-base/computation.ts b/src/mol-base/computation.ts index efaade35521c6e045065c311e7986ea8d775c771..76af815bca14741dc89fe7e8afa6770fd634b5af 100644 --- a/src/mol-base/computation.ts +++ b/src/mol-base/computation.ts @@ -5,7 +5,8 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import Scheduler from './scheduler' +import Scheduler from './utils/scheduler' +import timeNow from './utils/time' interface Computation<A> { (ctx?: Computation.Context): Promise<A> @@ -79,22 +80,7 @@ namespace Computation { return ret; } - declare var process: any; - declare var window: any; - - export const now: () => number = (function () { - if (typeof window !== 'undefined' && window.performance) { - const perf = window.performance; - return () => perf.now(); - } else if (typeof process !== 'undefined' && process.hrtime !== 'undefined') { - return () => { - let t = process.hrtime(); - return t[0] * 1000 + t[1] / 1000000; - }; - } else { - return () => +new Date(); - } - }()); + export const now = timeNow; /** A utility for splitting large computations into smaller parts. */ export interface Chunker { diff --git a/src/mol-base/scheduler.ts b/src/mol-base/utils/scheduler.ts similarity index 100% rename from src/mol-base/scheduler.ts rename to src/mol-base/utils/scheduler.ts diff --git a/src/mol-base/utils/time.ts b/src/mol-base/utils/time.ts new file mode 100644 index 0000000000000000000000000000000000000000..5a4290f13864f21c789e852fa08fa2fcebb5c341 --- /dev/null +++ b/src/mol-base/utils/time.ts @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +declare var process: any; +declare var window: any; + +const now: () => number = (function () { + if (typeof window !== 'undefined' && window.performance) { + const perf = window.performance; + return () => perf.now(); + } else if (typeof process !== 'undefined' && process.hrtime !== 'undefined') { + return () => { + let t = process.hrtime(); + return t[0] * 1000 + t[1] / 1000000; + }; + } else { + return () => +new Date(); + } +}()); + +export default now; \ No newline at end of file diff --git a/src/mol-base/utils/uuid.ts b/src/mol-base/utils/uuid.ts new file mode 100644 index 0000000000000000000000000000000000000000..cf12110a8b26f8b2c9bbd64e9989c807993c56a7 --- /dev/null +++ b/src/mol-base/utils/uuid.ts @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import now from './time' + +export default function generateUUID() { + let d = now(); + const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + const r = (d + Math.random()*16)%16 | 0; + d = Math.floor(d/16); + return (c==='x' ? r : (r&0x3|0x8)).toString(16); + }); + return uuid; +} \ No newline at end of file diff --git a/src/mol-data/_spec/atom-set.spec.ts b/src/mol-data/_spec/atom-set.spec.ts index 2c265acc93f5ccca5acd58c3807295f4807996a0..375e5ed379704fd4faca4fcadfeca1bd023c78c6 100644 --- a/src/mol-data/_spec/atom-set.spec.ts +++ b/src/mol-data/_spec/atom-set.spec.ts @@ -5,8 +5,8 @@ */ import OrderedSet from '../../mol-base/collections/integer/ordered-set' -import AtomSet from '../atom-set' -import Atom from '../atom' +import AtomSet from '../structure/atom-set' +import Atom from '../structure/atom' describe('atom set', () => { const p = (i: number, j: number) => Atom.create(i, j); diff --git a/src/mol-data/model.ts b/src/mol-data/model.ts index 689b170e5487421743ff41f5ea2ef0f478f5b8f2..bc5a486946ba4e8f5231a1536bd8767fd58bfce7 100644 --- a/src/mol-data/model.ts +++ b/src/mol-data/model.ts @@ -5,8 +5,9 @@ */ import * as Formats from './model/formats' -import CommonInterface from './model/common' -import MacromoleculeInterface from './model/macromolecule' +import CommonProperties from './model/common' +import MacromoleculeProperties from './model/macromolecule' +import Conformation from './model/conformation' import Segmentation from '../mol-base/collections/integer/segmentation' /** @@ -15,10 +16,19 @@ import Segmentation from '../mol-base/collections/integer/segmentation' * "Atoms" are integers in the range [0, atomCount). */ interface Model extends Readonly<{ + id: string, + sourceData: Formats.RawData, - common: CommonInterface, - macromolecule: MacromoleculeInterface + common: CommonProperties, + macromolecule: MacromoleculeProperties, + conformation: Conformation, + + // used for diffing. + version: { + data: number, + conformation: number + }, atomCount: number, segments: Readonly<{ diff --git a/src/mol-data/model/builders/mmcif.ts b/src/mol-data/model/builders/mmcif.ts index f2318b79460c8aee4fbfeec9513c1ab1776e2f61..9fe460f0c7bc2ec4b312b9084f30d903d9e862e4 100644 --- a/src/mol-data/model/builders/mmcif.ts +++ b/src/mol-data/model/builders/mmcif.ts @@ -9,6 +9,7 @@ import mmCIF from '../../../mol-io/reader/cif/schema/mmcif' import Model from '../../model' import Interval from '../../../mol-base/collections/integer/interval' import Segmentation from '../../../mol-base/collections/integer/segmentation' +import uuId from '../../../mol-base/utils/uuid' function findModelBounds(data: mmCIF, startIndex: number) { const num = data.atom_site.pdbx_PDB_model_num; @@ -23,7 +24,7 @@ function segment(data: mmCIF, bounds: Interval) { const start = Interval.start(bounds), end = Interval.end(bounds); const residues = [0], chains = [0], entities = [0]; - const { label_entity_id, auth_asym_id, auth_seq_id, pdbx_PDB_ins_code } = data.atom_site; + const { label_entity_id, auth_asym_id, auth_seq_id, pdbx_PDB_ins_code, label_comp_id } = data.atom_site; let offset = 1; for (let i = start + 1; i < end; i++) { @@ -31,7 +32,8 @@ function segment(data: mmCIF, bounds: Interval) { const newChain = newEntity || !auth_asym_id.areValuesEqual(i - 1, i); const newResidue = newChain || !auth_seq_id.areValuesEqual(i - 1, i) - || !pdbx_PDB_ins_code.areValuesEqual(i - 1, i); + || !pdbx_PDB_ins_code.areValuesEqual(i - 1, i) + || !label_comp_id.areValuesEqual(i - 1, i); if (newEntity) entities[entities.length] = offset; if (newResidue) residues[residues.length] = offset; @@ -53,9 +55,12 @@ function segment(data: mmCIF, bounds: Interval) { function createModel(raw: RawData, data: mmCIF, bounds: Interval): Model { const segments = segment(data, bounds); return { + id: uuId(), sourceData: raw, common: 0 as any, macromolecule: 0 as any, + conformation: 0 as any, + version: { data: 0, conformation: 0 }, atomCount: Interval.size(bounds), segments }; diff --git a/src/mol-data/conformation.ts b/src/mol-data/model/conformation.ts similarity index 100% rename from src/mol-data/conformation.ts rename to src/mol-data/model/conformation.ts diff --git a/src/mol-data/structure.ts b/src/mol-data/structure.ts index d4488fca58a6e1f7fd1bd682d3488ed4dff07b40..2a71a70378571b8a98e44cc7b287a43d2e29901f 100644 --- a/src/mol-data/structure.ts +++ b/src/mol-data/structure.ts @@ -4,41 +4,12 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import { Vec3, Mat4 } from '../mol-base/math/linear-algebra' -import AtomSet from './atom-set' -import Model from './model' -import Conformation from './conformation' - -export interface Operator extends Readonly<{ - name: string, - hkl: number[], // defaults to [0, 0, 0] for non symmetry entries - transform: Mat4, - // cache the inverse of the transform - inverse: Mat4, - // optimize the identity case - isIdentity: boolean -}> { } - -export interface Unit extends Readonly<{ - // Structure-level unique identifier of the unit. - id: number, - - // Provides access to the underlying data. - model: Model, - - // Separate the conformation from the data for faster/more straightforward dynamics - conformation: Conformation, - - // Determines the operation applied to this unit. - // The transform and and inverse are baked into the "getPosition" function - operator: Operator -}> { - // returns the untransformed position. Used for spatial queries. - getInvariantPosition(atom: number, slot: Vec3): Vec3 - - // gets the transformed position of the specified atom - getPosition(atom: number, slot: Vec3): Vec3 -} +//import { Vec3 } from '../mol-base/math/linear-algebra' +import AtomSet from './structure/atom-set' +import Unit from './structure/unit' +import * as Base from './structure/base' +//import Model from './model' +//import Operator from './structure/operator' // TODO: do "single model" version of the structure? export interface Structure extends Readonly<{ @@ -47,7 +18,8 @@ export interface Structure extends Readonly<{ }> { } export namespace Structure { - export const Empty: Structure = { units: {}, atoms: AtomSet.Empty }; + export const Empty = Base.Empty; + export const ofModel = Base.ofModel; // TODO: "lift" atom set operators // TODO: "diff" diff --git a/src/mol-data/atom-set.ts b/src/mol-data/structure/atom-set.ts similarity index 94% rename from src/mol-data/atom-set.ts rename to src/mol-data/structure/atom-set.ts index 7f3fd55abb5853e0cbccd346c9372884c79b8ae3..cca7fb966f7e226007eee08bceb177ad3c08b72c 100644 --- a/src/mol-data/atom-set.ts +++ b/src/mol-data/structure/atom-set.ts @@ -4,8 +4,8 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import OrderedSet from '../mol-base/collections/integer/ordered-set' -import Iterator from '../mol-base/collections/iterator' +import OrderedSet from '../../mol-base/collections/integer/ordered-set' +import Iterator from '../../mol-base/collections/iterator' import Atom from './atom' import * as Base from './atom-set/base' import createBuilder from './atom-set/builder' diff --git a/src/mol-data/atom-set/base.ts b/src/mol-data/structure/atom-set/base.ts similarity index 98% rename from src/mol-data/atom-set/base.ts rename to src/mol-data/structure/atom-set/base.ts index 3fba4183b0e09d9ee25214baa1dacedf3eee7b58..a198b5189e91c05b2e67c3ea5d06a495c22c09f8 100644 --- a/src/mol-data/atom-set/base.ts +++ b/src/mol-data/structure/atom-set/base.ts @@ -4,11 +4,11 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import OrderedSet from '../../mol-base/collections/integer/ordered-set' -import Iterator from '../../mol-base/collections/iterator' -import Interval from '../../mol-base/collections/integer/interval' -import { sortArray } from '../../mol-base/collections/sort' -import { hash1 } from '../../mol-base/collections/hash-functions' +import OrderedSet from '../../../mol-base/collections/integer/ordered-set' +import Iterator from '../../../mol-base/collections/iterator' +import Interval from '../../../mol-base/collections/integer/interval' +import { sortArray } from '../../../mol-base/collections/sort' +import { hash1 } from '../../../mol-base/collections/hash-functions' import Atom from '../atom' /** Long and painful implementation starts here */ diff --git a/src/mol-data/atom-set/builder.ts b/src/mol-data/structure/atom-set/builder.ts similarity index 92% rename from src/mol-data/atom-set/builder.ts rename to src/mol-data/structure/atom-set/builder.ts index 5682362869b40023ec42bec7c7261512690db7bd..06c8de16db153ee462e921a0dfb7f48c4593de0e 100644 --- a/src/mol-data/atom-set/builder.ts +++ b/src/mol-data/structure/atom-set/builder.ts @@ -5,8 +5,8 @@ */ import AtomSet from '../atom-set' -import OrderedSet from '../../mol-base/collections/integer/ordered-set' -import { sortArray } from '../../mol-base/collections/sort' +import OrderedSet from '../../../mol-base/collections/integer/ordered-set' +import { sortArray } from '../../../mol-base/collections/sort' class Builder { private keys: number[] = []; diff --git a/src/mol-data/atom-set/properties.ts b/src/mol-data/structure/atom-set/properties.ts similarity index 100% rename from src/mol-data/atom-set/properties.ts rename to src/mol-data/structure/atom-set/properties.ts diff --git a/src/mol-data/atom.ts b/src/mol-data/structure/atom.ts similarity index 91% rename from src/mol-data/atom.ts rename to src/mol-data/structure/atom.ts index 037a78c3ca2b210b07a34334bd2a0e838d08090c..7a6ef43aa18485e03dcee664642c34c2195f0f9c 100644 --- a/src/mol-data/atom.ts +++ b/src/mol-data/structure/atom.ts @@ -4,7 +4,7 @@ * @author David Sehnal <david.sehnal@gmail.com> */ -import Tuple from '../mol-base/collections/integer/tuple' +import Tuple from '../../mol-base/collections/integer/tuple' /** Atom pointer */ interface Atom { '@type': Tuple['@type'] } diff --git a/src/mol-data/structure/base.ts b/src/mol-data/structure/base.ts index 5a03161e3899d2b4b0b857c686273a270ba2122a..81a18c7908cf3c94c44746e192a0dd7cebccd09d 100644 --- a/src/mol-data/structure/base.ts +++ b/src/mol-data/structure/base.ts @@ -6,10 +6,32 @@ import Model from '../model' import Structure from '../structure' +import Unit from './unit' +import Operator from './operator' +import AtomSet from './atom-set' +import OrderedSet from '../../mol-base/collections/integer/ordered-set' -//export const Empty { } +class Builder { + private units = Object.create(null); + private atoms = Object.create(null); + + addUnit(unit: Unit) { this.units[unit.id] = unit; } + addAtoms(unitId: number, atoms: OrderedSet) { this.atoms[unitId] = atoms; } + + getStructure(): Structure { return { units: this.units, atoms: AtomSet.create(this.atoms) } } +} + +export const Empty: Structure = { units: {}, atoms: AtomSet.Empty }; export function ofModel(model: Model): Structure { - // TODO: create a unit for each chain in the model - return 0 as any; + const chains = model.segments.chains; + const builder = new Builder(); + + for (let c = 0; c < chains.count; c++) { + const unit = Unit.create(model, Operator.Identity); + builder.addUnit(unit); + builder.addAtoms(unit.id, OrderedSet.ofBounds(chains.segments[c], chains.segments[c + 1])); + } + + return builder.getStructure(); } \ No newline at end of file diff --git a/src/mol-data/structure/operator.ts b/src/mol-data/structure/operator.ts new file mode 100644 index 0000000000000000000000000000000000000000..484dd7590ef02326b08e28fe1dd55cfdf4b25b34 --- /dev/null +++ b/src/mol-data/structure/operator.ts @@ -0,0 +1,23 @@ +/** + * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import { Mat4 } from '../../mol-base/math/linear-algebra' + +interface Operator extends Readonly<{ + name: string, + hkl: number[], // defaults to [0, 0, 0] for non symmetry entries + transform: Mat4, + // cache the inverse of the transform + inverse: Mat4, + // optimize the identity case + isIdentity: boolean +}> { } + +namespace Operator { + export const Identity: Operator = { name: '1_555', hkl: [0, 0, 0], transform: Mat4.identity(), inverse: Mat4.identity(), isIdentity: true }; +} + +export default Operator \ No newline at end of file diff --git a/src/mol-data/structure/unit.ts b/src/mol-data/structure/unit.ts new file mode 100644 index 0000000000000000000000000000000000000000..ec81e9a7247f6e254bf01adcf6c5154a2267943d --- /dev/null +++ b/src/mol-data/structure/unit.ts @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info. + * + * @author David Sehnal <david.sehnal@gmail.com> + */ + +import Model from '../model' +import Operator from './operator' + +interface Unit extends Readonly<{ + // Structure-level unique identifier of the unit. + id: number, + + // Provides access to the underlying data. + model: Model, + + // Determines the operation applied to this unit. + // The transform and and inverse are baked into the "getPosition" function + operator: Operator +}> { + // // returns the untransformed position. Used for spatial queries. + // getInvariantPosition(atom: number, slot: Vec3): Vec3 + + // // gets the transformed position of the specified atom + // getPosition(atom: number, slot: Vec3): Vec3 +} + +namespace Unit { + export function create(model: Model, operator: Operator): Unit { + return { id: nextUnitId(), model, operator }; + } +} + +export default Unit; + +let _id = 0; +function nextUnitId() { + const ret = _id; + _id = (_id + 1) % 0x3fffffff; + return ret; +} \ No newline at end of file diff --git a/src/perf-tests/sets.ts b/src/perf-tests/sets.ts index f5d4f394cee56d92d62d3549fd1737789ad04070..6d3a2cbf1a6487c702fe0ccfc77eb7cd755eb113 100644 --- a/src/perf-tests/sets.ts +++ b/src/perf-tests/sets.ts @@ -1,7 +1,7 @@ import * as B from 'benchmark' import Tuple from '../mol-base/collections/integer/tuple' import OrdSet from '../mol-base/collections/integer/ordered-set' -import AtomSet from '../mol-data/atom-set' +import AtomSet from '../mol-data/structure/atom-set' import Segmentation from '../mol-base/collections/integer/segmentation' export namespace Iteration { @@ -203,8 +203,8 @@ export namespace Union { export namespace Build { function createSorted() { const b = AtomSet.SortedBuilder(AtomSet.Empty); - for (let i = 0; i < 100; i++) { - for (let j = 0; j < 100; j++) { + for (let i = 0; i < 10; i++) { + for (let j = 0; j < 1000; j++) { b.add(i, j); } } @@ -213,9 +213,9 @@ export namespace Build { function createByUnit() { const b = AtomSet.SortedBuilder(AtomSet.Empty); - for (let i = 0; i < 100; i++) { + for (let i = 0; i < 10; i++) { b.beginUnit(); - for (let j = 0; j < 100; j++) { + for (let j = 0; j < 1000; j++) { b.addToUnit(j); } b.commitUnit(i); @@ -284,7 +284,9 @@ export function testSegments() { } } -testSegments(); +Build.run(); + +//testSegments(); //Tuples.run();